diff options
-rw-r--r-- | include/sound/soc-dapm.h | 199 | ||||
-rw-r--r-- | include/sound/soc-dpcm.h | 2 | ||||
-rw-r--r-- | include/sound/soc.h | 29 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 52 | ||||
-rw-r--r-- | sound/soc/codecs/twl6040.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8903.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wm8995.c | 5 | ||||
-rw-r--r-- | sound/soc/codecs/wm_hubs.c | 8 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 804 | ||||
-rw-r--r-- | sound/soc/soc-pcm.c | 10 |
11 files changed, 628 insertions, 493 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 3e479f4e15f5..c728d28ae9a5 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -70,121 +70,144 @@ struct device; | |||
70 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ | 70 | .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ |
71 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} | 71 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} |
72 | 72 | ||
73 | #define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \ | ||
74 | .reg = wreg, .mask = 1, .shift = wshift, \ | ||
75 | .on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0 | ||
76 | |||
73 | /* path domain */ | 77 | /* path domain */ |
74 | #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ | 78 | #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ |
75 | wcontrols, wncontrols) \ | 79 | wcontrols, wncontrols) \ |
76 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 80 | { .id = snd_soc_dapm_pga, .name = wname, \ |
77 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} | 81 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
82 | .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} | ||
78 | #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ | 83 | #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ |
79 | wcontrols, wncontrols) \ | 84 | wcontrols, wncontrols) \ |
80 | { .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ | 85 | { .id = snd_soc_dapm_out_drv, .name = wname, \ |
81 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} | 86 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
87 | .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} | ||
82 | #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ | 88 | #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ |
83 | wcontrols, wncontrols)\ | 89 | wcontrols, wncontrols)\ |
84 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 90 | { .id = snd_soc_dapm_mixer, .name = wname, \ |
85 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} | 91 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
92 | .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} | ||
86 | #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ | 93 | #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ |
87 | wcontrols, wncontrols)\ | 94 | wcontrols, wncontrols)\ |
88 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ | 95 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ |
89 | .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ | 96 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
90 | .num_kcontrols = wncontrols} | 97 | .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} |
91 | #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ | 98 | #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ |
92 | { .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ | 99 | { .id = snd_soc_dapm_micbias, .name = wname, \ |
93 | .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0} | 100 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
101 | .kcontrol_news = NULL, .num_kcontrols = 0} | ||
94 | #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ | 102 | #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ |
95 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ | 103 | { .id = snd_soc_dapm_switch, .name = wname, \ |
96 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} | 104 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
105 | .kcontrol_news = wcontrols, .num_kcontrols = 1} | ||
97 | #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 106 | #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
98 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 107 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, \ |
99 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} | 108 | .kcontrol_news = wcontrols, .num_kcontrols = 1} |
100 | #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 109 | #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
101 | { .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 110 | { .id = snd_soc_dapm_virt_mux, .name = wname, \ |
102 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} | 111 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
112 | .kcontrol_news = wcontrols, .num_kcontrols = 1} | ||
103 | #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 113 | #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
104 | { .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \ | 114 | { .id = snd_soc_dapm_value_mux, .name = wname, \ |
105 | .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ | 115 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
106 | .num_kcontrols = 1} | 116 | .kcontrol_news = wcontrols, .num_kcontrols = 1} |
107 | 117 | ||
108 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ | 118 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ |
109 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ | 119 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ |
110 | wcontrols) \ | 120 | wcontrols) \ |
111 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 121 | { .id = snd_soc_dapm_pga, .name = wname, \ |
112 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} | 122 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
123 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} | ||
113 | #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ | 124 | #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ |
114 | wcontrols)\ | 125 | wcontrols)\ |
115 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 126 | { .id = snd_soc_dapm_mixer, .name = wname, \ |
116 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} | 127 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
128 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} | ||
117 | #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ | 129 | #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ |
118 | wcontrols)\ | 130 | wcontrols)\ |
119 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ | 131 | { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \ |
120 | .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ | 132 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
121 | .num_kcontrols = ARRAY_SIZE(wcontrols)} | 133 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} |
122 | 134 | ||
123 | /* path domain with event - event handler must return 0 for success */ | 135 | /* path domain with event - event handler must return 0 for success */ |
124 | #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ | 136 | #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ |
125 | wncontrols, wevent, wflags) \ | 137 | wncontrols, wevent, wflags) \ |
126 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 138 | { .id = snd_soc_dapm_pga, .name = wname, \ |
127 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ | 139 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
140 | .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ | ||
128 | .event = wevent, .event_flags = wflags} | 141 | .event = wevent, .event_flags = wflags} |
129 | #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \ | 142 | #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \ |
130 | wncontrols, wevent, wflags) \ | 143 | wncontrols, wevent, wflags) \ |
131 | { .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ | 144 | { .id = snd_soc_dapm_out_drv, .name = wname, \ |
132 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ | 145 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
146 | .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ | ||
133 | .event = wevent, .event_flags = wflags} | 147 | .event = wevent, .event_flags = wflags} |
134 | #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ | 148 | #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ |
135 | wncontrols, wevent, wflags) \ | 149 | wncontrols, wevent, wflags) \ |
136 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 150 | { .id = snd_soc_dapm_mixer, .name = wname, \ |
137 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ | 151 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
152 | .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ | ||
138 | .event = wevent, .event_flags = wflags} | 153 | .event = wevent, .event_flags = wflags} |
139 | #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ | 154 | #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ |
140 | wcontrols, wncontrols, wevent, wflags) \ | 155 | wcontrols, wncontrols, wevent, wflags) \ |
141 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 156 | { .id = snd_soc_dapm_mixer, .name = wname, \ |
142 | .invert = winvert, .kcontrol_news = wcontrols, \ | 157 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
158 | .kcontrol_news = wcontrols, \ | ||
143 | .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} | 159 | .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} |
144 | #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ | 160 | #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ |
145 | wevent, wflags) \ | 161 | wevent, wflags) \ |
146 | { .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ | 162 | { .id = snd_soc_dapm_switch, .name = wname, \ |
147 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ | 163 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
164 | .kcontrol_news = wcontrols, .num_kcontrols = 1, \ | ||
148 | .event = wevent, .event_flags = wflags} | 165 | .event = wevent, .event_flags = wflags} |
149 | #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ | 166 | #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ |
150 | wevent, wflags) \ | 167 | wevent, wflags) \ |
151 | { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 168 | { .id = snd_soc_dapm_mux, .name = wname, \ |
152 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ | 169 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
170 | .kcontrol_news = wcontrols, .num_kcontrols = 1, \ | ||
153 | .event = wevent, .event_flags = wflags} | 171 | .event = wevent, .event_flags = wflags} |
154 | #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ | 172 | #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ |
155 | wevent, wflags) \ | 173 | wevent, wflags) \ |
156 | { .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ | 174 | { .id = snd_soc_dapm_virt_mux, .name = wname, \ |
157 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ | 175 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
176 | .kcontrol_news = wcontrols, .num_kcontrols = 1, \ | ||
158 | .event = wevent, .event_flags = wflags} | 177 | .event = wevent, .event_flags = wflags} |
159 | 178 | ||
160 | /* additional sequencing control within an event type */ | 179 | /* additional sequencing control within an event type */ |
161 | #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ | 180 | #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ |
162 | wevent, wflags) \ | 181 | wevent, wflags) \ |
163 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 182 | { .id = snd_soc_dapm_pga, .name = wname, \ |
164 | .invert = winvert, .event = wevent, .event_flags = wflags, \ | 183 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
184 | .event = wevent, .event_flags = wflags, \ | ||
165 | .subseq = wsubseq} | 185 | .subseq = wsubseq} |
166 | #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \ | 186 | #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \ |
167 | wflags) \ | 187 | wflags) \ |
168 | { .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \ | 188 | { .id = snd_soc_dapm_supply, .name = wname, \ |
169 | .shift = wshift, .invert = winvert, .event = wevent, \ | 189 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
170 | .event_flags = wflags, .subseq = wsubseq} | 190 | .event = wevent, .event_flags = wflags, .subseq = wsubseq} |
171 | 191 | ||
172 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ | 192 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ |
173 | #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ | 193 | #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ |
174 | wevent, wflags) \ | 194 | wevent, wflags) \ |
175 | { .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ | 195 | { .id = snd_soc_dapm_pga, .name = wname, \ |
176 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ | 196 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
197 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ | ||
177 | .event = wevent, .event_flags = wflags} | 198 | .event = wevent, .event_flags = wflags} |
178 | #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ | 199 | #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ |
179 | wevent, wflags) \ | 200 | wevent, wflags) \ |
180 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 201 | { .id = snd_soc_dapm_mixer, .name = wname, \ |
181 | .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ | 202 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
203 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ | ||
182 | .event = wevent, .event_flags = wflags} | 204 | .event = wevent, .event_flags = wflags} |
183 | #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ | 205 | #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ |
184 | wcontrols, wevent, wflags) \ | 206 | wcontrols, wevent, wflags) \ |
185 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ | 207 | { .id = snd_soc_dapm_mixer, .name = wname, \ |
186 | .invert = winvert, .kcontrol_news = wcontrols, \ | 208 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
187 | .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags} | 209 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ |
210 | .event = wevent, .event_flags = wflags} | ||
188 | 211 | ||
189 | /* events that are pre and post DAPM */ | 212 | /* events that are pre and post DAPM */ |
190 | #define SND_SOC_DAPM_PRE(wname, wevent) \ | 213 | #define SND_SOC_DAPM_PRE(wname, wevent) \ |
@@ -199,35 +222,36 @@ struct device; | |||
199 | /* stream domain */ | 222 | /* stream domain */ |
200 | #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ | 223 | #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ |
201 | { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ | 224 | { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ |
202 | .reg = wreg, .shift = wshift, .invert = winvert } | 225 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } |
203 | #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ | 226 | #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ |
204 | wevent, wflags) \ | 227 | wevent, wflags) \ |
205 | { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ | 228 | { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ |
206 | .reg = wreg, .shift = wshift, .invert = winvert, \ | 229 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
207 | .event = wevent, .event_flags = wflags } | 230 | .event = wevent, .event_flags = wflags } |
208 | #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ | 231 | #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ |
209 | { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ | 232 | { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ |
210 | .reg = wreg, .shift = wshift, .invert = winvert } | 233 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } |
211 | #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ | 234 | #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ |
212 | wevent, wflags) \ | 235 | wevent, wflags) \ |
213 | { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ | 236 | { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ |
214 | .reg = wreg, .shift = wshift, .invert = winvert, \ | 237 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
215 | .event = wevent, .event_flags = wflags } | 238 | .event = wevent, .event_flags = wflags } |
216 | #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ | 239 | #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ |
217 | { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ | 240 | { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ |
218 | .shift = wshift, .invert = winvert} | 241 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) } |
219 | #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \ | 242 | #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \ |
220 | wevent, wflags) \ | 243 | wevent, wflags) \ |
221 | { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ | 244 | { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ |
222 | .shift = wshift, .invert = winvert, \ | 245 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
223 | .event = wevent, .event_flags = wflags} | 246 | .event = wevent, .event_flags = wflags} |
247 | |||
224 | #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ | 248 | #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ |
225 | { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ | 249 | { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ |
226 | .shift = wshift, .invert = winvert} | 250 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } |
227 | #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \ | 251 | #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \ |
228 | wevent, wflags) \ | 252 | wevent, wflags) \ |
229 | { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ | 253 | { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \ |
230 | .shift = wshift, .invert = winvert, \ | 254 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
231 | .event = wevent, .event_flags = wflags} | 255 | .event = wevent, .event_flags = wflags} |
232 | #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ | 256 | #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ |
233 | { .id = snd_soc_dapm_clock_supply, .name = wname, \ | 257 | { .id = snd_soc_dapm_clock_supply, .name = wname, \ |
@@ -241,14 +265,14 @@ struct device; | |||
241 | .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ | 265 | .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ |
242 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} | 266 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} |
243 | #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \ | 267 | #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \ |
244 | { .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \ | 268 | { .id = snd_soc_dapm_supply, .name = wname, \ |
245 | .shift = wshift, .invert = winvert, .event = wevent, \ | 269 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
246 | .event_flags = wflags} | 270 | .event = wevent, .event_flags = wflags} |
247 | #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \ | 271 | #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \ |
248 | { .id = snd_soc_dapm_regulator_supply, .name = wname, \ | 272 | { .id = snd_soc_dapm_regulator_supply, .name = wname, \ |
249 | .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ | 273 | .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ |
250 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | 274 | .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ |
251 | .invert = wflags} | 275 | .on_val = wflags} |
252 | 276 | ||
253 | 277 | ||
254 | /* dapm kcontrol types */ | 278 | /* dapm kcontrol types */ |
@@ -256,14 +280,26 @@ struct device; | |||
256 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 280 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
257 | .info = snd_soc_info_volsw, \ | 281 | .info = snd_soc_info_volsw, \ |
258 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ | 282 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ |
259 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 283 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } |
284 | #define SOC_DAPM_SINGLE_AUTODISABLE(xname, reg, shift, max, invert) \ | ||
285 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
286 | .info = snd_soc_info_volsw, \ | ||
287 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ | ||
288 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) } | ||
260 | #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ | 289 | #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ |
261 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 290 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
262 | .info = snd_soc_info_volsw, \ | 291 | .info = snd_soc_info_volsw, \ |
263 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 292 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
264 | .tlv.p = (tlv_array), \ | 293 | .tlv.p = (tlv_array), \ |
265 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ | 294 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ |
266 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 295 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } |
296 | #define SOC_DAPM_SINGLE_TLV_AUTODISABLE(xname, reg, shift, max, invert, tlv_array) \ | ||
297 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
298 | .info = snd_soc_info_volsw, \ | ||
299 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
300 | .tlv.p = (tlv_array), \ | ||
301 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ | ||
302 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } | ||
267 | #define SOC_DAPM_ENUM(xname, xenum) \ | 303 | #define SOC_DAPM_ENUM(xname, xenum) \ |
268 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 304 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
269 | .info = snd_soc_info_enum_double, \ | 305 | .info = snd_soc_info_enum_double, \ |
@@ -333,6 +369,7 @@ struct snd_soc_dapm_route; | |||
333 | struct snd_soc_dapm_context; | 369 | struct snd_soc_dapm_context; |
334 | struct regulator; | 370 | struct regulator; |
335 | struct snd_soc_dapm_widget_list; | 371 | struct snd_soc_dapm_widget_list; |
372 | struct snd_soc_dapm_update; | ||
336 | 373 | ||
337 | int dapm_reg_event(struct snd_soc_dapm_widget *w, | 374 | int dapm_reg_event(struct snd_soc_dapm_widget *w, |
338 | struct snd_kcontrol *kcontrol, int event); | 375 | struct snd_kcontrol *kcontrol, int event); |
@@ -391,10 +428,12 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | |||
391 | void snd_soc_dapm_shutdown(struct snd_soc_card *card); | 428 | void snd_soc_dapm_shutdown(struct snd_soc_card *card); |
392 | 429 | ||
393 | /* external DAPM widget events */ | 430 | /* external DAPM widget events */ |
394 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 431 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, |
395 | struct snd_kcontrol *kcontrol, int connect); | 432 | struct snd_kcontrol *kcontrol, int connect, |
396 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 433 | struct snd_soc_dapm_update *update); |
397 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e); | 434 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, |
435 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e, | ||
436 | struct snd_soc_dapm_update *update); | ||
398 | 437 | ||
399 | /* dapm sys fs - used by the core */ | 438 | /* dapm sys fs - used by the core */ |
400 | int snd_soc_dapm_sys_add(struct device *dev); | 439 | int snd_soc_dapm_sys_add(struct device *dev); |
@@ -424,6 +463,8 @@ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); | |||
424 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | 463 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, |
425 | struct snd_soc_dapm_widget_list **list); | 464 | struct snd_soc_dapm_widget_list **list); |
426 | 465 | ||
466 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol); | ||
467 | |||
427 | /* dapm widget types */ | 468 | /* dapm widget types */ |
428 | enum snd_soc_dapm_type { | 469 | enum snd_soc_dapm_type { |
429 | snd_soc_dapm_input = 0, /* input pin */ | 470 | snd_soc_dapm_input = 0, /* input pin */ |
@@ -455,6 +496,7 @@ enum snd_soc_dapm_type { | |||
455 | snd_soc_dapm_dai_in, /* link to DAI structure */ | 496 | snd_soc_dapm_dai_in, /* link to DAI structure */ |
456 | snd_soc_dapm_dai_out, | 497 | snd_soc_dapm_dai_out, |
457 | snd_soc_dapm_dai_link, /* link between two DAI structures */ | 498 | snd_soc_dapm_dai_link, /* link between two DAI structures */ |
499 | snd_soc_dapm_kcontrol, /* Auto-disabled kcontrol */ | ||
458 | }; | 500 | }; |
459 | 501 | ||
460 | enum snd_soc_dapm_subclass { | 502 | enum snd_soc_dapm_subclass { |
@@ -485,7 +527,6 @@ struct snd_soc_dapm_path { | |||
485 | /* source (input) and sink (output) widgets */ | 527 | /* source (input) and sink (output) widgets */ |
486 | struct snd_soc_dapm_widget *source; | 528 | struct snd_soc_dapm_widget *source; |
487 | struct snd_soc_dapm_widget *sink; | 529 | struct snd_soc_dapm_widget *sink; |
488 | struct snd_kcontrol *kcontrol; | ||
489 | 530 | ||
490 | /* status */ | 531 | /* status */ |
491 | u32 connect:1; /* source and sink widgets are connected */ | 532 | u32 connect:1; /* source and sink widgets are connected */ |
@@ -498,6 +539,7 @@ struct snd_soc_dapm_path { | |||
498 | 539 | ||
499 | struct list_head list_source; | 540 | struct list_head list_source; |
500 | struct list_head list_sink; | 541 | struct list_head list_sink; |
542 | struct list_head list_kcontrol; | ||
501 | struct list_head list; | 543 | struct list_head list; |
502 | }; | 544 | }; |
503 | 545 | ||
@@ -518,12 +560,10 @@ struct snd_soc_dapm_widget { | |||
518 | /* dapm control */ | 560 | /* dapm control */ |
519 | int reg; /* negative reg = no direct dapm */ | 561 | int reg; /* negative reg = no direct dapm */ |
520 | unsigned char shift; /* bits to shift */ | 562 | unsigned char shift; /* bits to shift */ |
521 | unsigned int value; /* widget current value */ | ||
522 | unsigned int mask; /* non-shifted mask */ | 563 | unsigned int mask; /* non-shifted mask */ |
523 | unsigned int on_val; /* on state value */ | 564 | unsigned int on_val; /* on state value */ |
524 | unsigned int off_val; /* off state value */ | 565 | unsigned int off_val; /* off state value */ |
525 | unsigned char power:1; /* block power status */ | 566 | unsigned char power:1; /* block power status */ |
526 | unsigned char invert:1; /* invert the power bit */ | ||
527 | unsigned char active:1; /* active stream on DAC, ADC's */ | 567 | unsigned char active:1; /* active stream on DAC, ADC's */ |
528 | unsigned char connected:1; /* connected codec pin */ | 568 | unsigned char connected:1; /* connected codec pin */ |
529 | unsigned char new:1; /* cnew complete */ | 569 | unsigned char new:1; /* cnew complete */ |
@@ -559,7 +599,6 @@ struct snd_soc_dapm_widget { | |||
559 | }; | 599 | }; |
560 | 600 | ||
561 | struct snd_soc_dapm_update { | 601 | struct snd_soc_dapm_update { |
562 | struct snd_soc_dapm_widget *widget; | ||
563 | struct snd_kcontrol *kcontrol; | 602 | struct snd_kcontrol *kcontrol; |
564 | int reg; | 603 | int reg; |
565 | int mask; | 604 | int mask; |
@@ -573,8 +612,6 @@ struct snd_soc_dapm_context { | |||
573 | struct delayed_work delayed_work; | 612 | struct delayed_work delayed_work; |
574 | unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ | 613 | unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ |
575 | 614 | ||
576 | struct snd_soc_dapm_update *update; | ||
577 | |||
578 | void (*seq_notifier)(struct snd_soc_dapm_context *, | 615 | void (*seq_notifier)(struct snd_soc_dapm_context *, |
579 | enum snd_soc_dapm_type, int); | 616 | enum snd_soc_dapm_type, int); |
580 | 617 | ||
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 04598f1efd77..047d657c331c 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h | |||
@@ -133,6 +133,6 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream, | |||
133 | /* internal use only */ | 133 | /* internal use only */ |
134 | int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute); | 134 | int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute); |
135 | int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); | 135 | int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); |
136 | int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *); | 136 | int soc_dpcm_runtime_update(struct snd_soc_card *); |
137 | 137 | ||
138 | #endif | 138 | #endif |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 6f86a4187f58..d57a04e7553d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -30,13 +30,13 @@ | |||
30 | /* | 30 | /* |
31 | * Convenience kcontrol builders | 31 | * Convenience kcontrol builders |
32 | */ | 32 | */ |
33 | #define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \ | 33 | #define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert, xautodisable) \ |
34 | ((unsigned long)&(struct soc_mixer_control) \ | 34 | ((unsigned long)&(struct soc_mixer_control) \ |
35 | {.reg = xreg, .rreg = xreg, .shift = shift_left, \ | 35 | {.reg = xreg, .rreg = xreg, .shift = shift_left, \ |
36 | .rshift = shift_right, .max = xmax, .platform_max = xmax, \ | 36 | .rshift = shift_right, .max = xmax, .platform_max = xmax, \ |
37 | .invert = xinvert}) | 37 | .invert = xinvert, .autodisable = xautodisable}) |
38 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ | 38 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \ |
39 | SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert) | 39 | SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable) |
40 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ | 40 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ |
41 | ((unsigned long)&(struct soc_mixer_control) \ | 41 | ((unsigned long)&(struct soc_mixer_control) \ |
42 | {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) | 42 | {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) |
@@ -52,7 +52,7 @@ | |||
52 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 52 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
53 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 53 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
54 | .put = snd_soc_put_volsw, \ | 54 | .put = snd_soc_put_volsw, \ |
55 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 55 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } |
56 | #define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \ | 56 | #define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \ |
57 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 57 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
58 | .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ | 58 | .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ |
@@ -68,7 +68,7 @@ | |||
68 | .tlv.p = (tlv_array), \ | 68 | .tlv.p = (tlv_array), \ |
69 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 69 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
70 | .put = snd_soc_put_volsw, \ | 70 | .put = snd_soc_put_volsw, \ |
71 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 71 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } |
72 | #define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \ | 72 | #define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \ |
73 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 73 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
74 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 74 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
@@ -97,7 +97,7 @@ | |||
97 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | 97 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ |
98 | .put = snd_soc_put_volsw, \ | 98 | .put = snd_soc_put_volsw, \ |
99 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ | 99 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ |
100 | max, invert) } | 100 | max, invert, 0) } |
101 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ | 101 | #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ |
102 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 102 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
103 | .info = snd_soc_info_volsw, \ | 103 | .info = snd_soc_info_volsw, \ |
@@ -119,7 +119,7 @@ | |||
119 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | 119 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ |
120 | .put = snd_soc_put_volsw, \ | 120 | .put = snd_soc_put_volsw, \ |
121 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ | 121 | .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ |
122 | max, invert) } | 122 | max, invert, 0) } |
123 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ | 123 | #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ |
124 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 124 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
125 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 125 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
@@ -190,14 +190,14 @@ | |||
190 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 190 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
191 | .info = snd_soc_info_volsw, \ | 191 | .info = snd_soc_info_volsw, \ |
192 | .get = xhandler_get, .put = xhandler_put, \ | 192 | .get = xhandler_get, .put = xhandler_put, \ |
193 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } | 193 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) } |
194 | #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\ | 194 | #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\ |
195 | xhandler_get, xhandler_put) \ | 195 | xhandler_get, xhandler_put) \ |
196 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 196 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
197 | .info = snd_soc_info_volsw, \ | 197 | .info = snd_soc_info_volsw, \ |
198 | .get = xhandler_get, .put = xhandler_put, \ | 198 | .get = xhandler_get, .put = xhandler_put, \ |
199 | .private_value = \ | 199 | .private_value = \ |
200 | SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) } | 200 | SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert, 0) } |
201 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ | 201 | #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ |
202 | xhandler_get, xhandler_put, tlv_array) \ | 202 | xhandler_get, xhandler_put, tlv_array) \ |
203 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 203 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
@@ -206,7 +206,7 @@ | |||
206 | .tlv.p = (tlv_array), \ | 206 | .tlv.p = (tlv_array), \ |
207 | .info = snd_soc_info_volsw, \ | 207 | .info = snd_soc_info_volsw, \ |
208 | .get = xhandler_get, .put = xhandler_put, \ | 208 | .get = xhandler_get, .put = xhandler_put, \ |
209 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } | 209 | .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) } |
210 | #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ | 210 | #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ |
211 | xhandler_get, xhandler_put, tlv_array) \ | 211 | xhandler_get, xhandler_put, tlv_array) \ |
212 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 212 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
@@ -216,7 +216,7 @@ | |||
216 | .info = snd_soc_info_volsw, \ | 216 | .info = snd_soc_info_volsw, \ |
217 | .get = xhandler_get, .put = xhandler_put, \ | 217 | .get = xhandler_get, .put = xhandler_put, \ |
218 | .private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \ | 218 | .private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \ |
219 | xmax, xinvert) } | 219 | xmax, xinvert, 0) } |
220 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ | 220 | #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ |
221 | xhandler_get, xhandler_put, tlv_array) \ | 221 | xhandler_get, xhandler_put, tlv_array) \ |
222 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 222 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
@@ -1038,6 +1038,7 @@ struct snd_soc_card { | |||
1038 | /* Generic DAPM context for the card */ | 1038 | /* Generic DAPM context for the card */ |
1039 | struct snd_soc_dapm_context dapm; | 1039 | struct snd_soc_dapm_context dapm; |
1040 | struct snd_soc_dapm_stats dapm_stats; | 1040 | struct snd_soc_dapm_stats dapm_stats; |
1041 | struct snd_soc_dapm_update *update; | ||
1041 | 1042 | ||
1042 | #ifdef CONFIG_DEBUG_FS | 1043 | #ifdef CONFIG_DEBUG_FS |
1043 | struct dentry *debugfs_card_root; | 1044 | struct dentry *debugfs_card_root; |
@@ -1083,7 +1084,9 @@ struct snd_soc_pcm_runtime { | |||
1083 | /* mixer control */ | 1084 | /* mixer control */ |
1084 | struct soc_mixer_control { | 1085 | struct soc_mixer_control { |
1085 | int min, max, platform_max; | 1086 | int min, max, platform_max; |
1086 | unsigned int reg, rreg, shift, rshift, invert; | 1087 | unsigned int reg, rreg, shift, rshift; |
1088 | unsigned int invert:1; | ||
1089 | unsigned int autodisable:1; | ||
1087 | }; | 1090 | }; |
1088 | 1091 | ||
1089 | struct soc_bytes { | 1092 | struct soc_bytes { |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index e5b926883131..fec0db04262d 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -138,8 +138,7 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { | |||
138 | static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | 138 | static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, |
139 | struct snd_ctl_elem_value *ucontrol) | 139 | struct snd_ctl_elem_value *ucontrol) |
140 | { | 140 | { |
141 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 141 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
142 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
143 | struct soc_mixer_control *mc = | 142 | struct soc_mixer_control *mc = |
144 | (struct soc_mixer_control *)kcontrol->private_value; | 143 | (struct soc_mixer_control *)kcontrol->private_value; |
145 | unsigned int reg = mc->reg; | 144 | unsigned int reg = mc->reg; |
@@ -147,10 +146,9 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
147 | int max = mc->max; | 146 | int max = mc->max; |
148 | unsigned int mask = (1 << fls(max)) - 1; | 147 | unsigned int mask = (1 << fls(max)) - 1; |
149 | unsigned int invert = mc->invert; | 148 | unsigned int invert = mc->invert; |
150 | unsigned short val, val_mask; | 149 | unsigned short val; |
151 | int ret; | 150 | struct snd_soc_dapm_update update; |
152 | struct snd_soc_dapm_path *path; | 151 | int connect, change; |
153 | int found = 0; | ||
154 | 152 | ||
155 | val = (ucontrol->value.integer.value[0] & mask); | 153 | val = (ucontrol->value.integer.value[0] & mask); |
156 | 154 | ||
@@ -158,42 +156,26 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
158 | if (val) | 156 | if (val) |
159 | val = mask; | 157 | val = mask; |
160 | 158 | ||
159 | connect = !!val; | ||
160 | |||
161 | if (invert) | 161 | if (invert) |
162 | val = mask - val; | 162 | val = mask - val; |
163 | val_mask = mask << shift; | ||
164 | val = val << shift; | ||
165 | |||
166 | mutex_lock(&widget->codec->mutex); | ||
167 | 163 | ||
168 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { | 164 | mask <<= shift; |
169 | /* find dapm widget path assoc with kcontrol */ | 165 | val <<= shift; |
170 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | ||
171 | if (path->kcontrol != kcontrol) | ||
172 | continue; | ||
173 | 166 | ||
174 | /* found, now check type */ | 167 | change = snd_soc_test_bits(codec, val, mask, reg); |
175 | found = 1; | 168 | if (change) { |
176 | if (val) | 169 | update.kcontrol = kcontrol; |
177 | /* new connection */ | 170 | update.reg = reg; |
178 | path->connect = invert ? 0 : 1; | 171 | update.mask = mask; |
179 | else | 172 | update.val = val; |
180 | /* old connection must be powered down */ | ||
181 | path->connect = invert ? 1 : 0; | ||
182 | 173 | ||
183 | dapm_mark_dirty(path->source, "tlv320aic3x source"); | 174 | snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect, |
184 | dapm_mark_dirty(path->sink, "tlv320aic3x sink"); | 175 | &update); |
185 | |||
186 | break; | ||
187 | } | ||
188 | } | 176 | } |
189 | 177 | ||
190 | mutex_unlock(&widget->codec->mutex); | 178 | return change; |
191 | |||
192 | if (found) | ||
193 | snd_soc_dapm_sync(widget->dapm); | ||
194 | |||
195 | ret = snd_soc_update_bits_locked(widget->codec, reg, val_mask, val); | ||
196 | return ret; | ||
197 | } | 179 | } |
198 | 180 | ||
199 | /* | 181 | /* |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 44621ddc332d..d6c5bf14179a 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -437,9 +437,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data) | |||
437 | static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol, | 437 | static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol, |
438 | struct snd_ctl_elem_value *ucontrol) | 438 | struct snd_ctl_elem_value *ucontrol) |
439 | { | 439 | { |
440 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 440 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
441 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
442 | struct snd_soc_codec *codec = widget->codec; | ||
443 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 441 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
444 | unsigned int val; | 442 | unsigned int val; |
445 | 443 | ||
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index fa24cedee687..eebcb1da3b7b 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -364,9 +364,7 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm, | |||
364 | static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, | 364 | static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, |
365 | struct snd_ctl_elem_value *ucontrol) | 365 | struct snd_ctl_elem_value *ucontrol) |
366 | { | 366 | { |
367 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 367 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
368 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
369 | struct snd_soc_codec *codec = widget->codec; | ||
370 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | 368 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); |
371 | u16 reg; | 369 | u16 reg; |
372 | int ret; | 370 | int ret; |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index ba832b77c543..eee2a01f2691 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -1437,9 +1437,7 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | |||
1437 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, | 1437 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, |
1438 | struct snd_ctl_elem_value *ucontrol) | 1438 | struct snd_ctl_elem_value *ucontrol) |
1439 | { | 1439 | { |
1440 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 1440 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
1441 | struct snd_soc_dapm_widget *w = wlist->widgets[0]; | ||
1442 | struct snd_soc_codec *codec = w->codec; | ||
1443 | int ret; | 1441 | int ret; |
1444 | 1442 | ||
1445 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | 1443 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); |
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 90a65c427541..da2899e6c401 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -549,12 +549,9 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source, | |||
549 | static int wm8995_put_class_w(struct snd_kcontrol *kcontrol, | 549 | static int wm8995_put_class_w(struct snd_kcontrol *kcontrol, |
550 | struct snd_ctl_elem_value *ucontrol) | 550 | struct snd_ctl_elem_value *ucontrol) |
551 | { | 551 | { |
552 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 552 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
553 | struct snd_soc_dapm_widget *w = wlist->widgets[0]; | ||
554 | struct snd_soc_codec *codec; | ||
555 | int ret; | 553 | int ret; |
556 | 554 | ||
557 | codec = w->codec; | ||
558 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | 555 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); |
559 | wm8995_update_class_w(codec); | 556 | wm8995_update_class_w(codec); |
560 | return ret; | 557 | return ret; |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 2d9e099415a5..8b50e5958de5 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -699,9 +699,7 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w); | |||
699 | static int class_w_put_volsw(struct snd_kcontrol *kcontrol, | 699 | static int class_w_put_volsw(struct snd_kcontrol *kcontrol, |
700 | struct snd_ctl_elem_value *ucontrol) | 700 | struct snd_ctl_elem_value *ucontrol) |
701 | { | 701 | { |
702 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 702 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
703 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
704 | struct snd_soc_codec *codec = widget->codec; | ||
705 | int ret; | 703 | int ret; |
706 | 704 | ||
707 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); | 705 | ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); |
@@ -721,9 +719,7 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol, | |||
721 | static int class_w_put_double(struct snd_kcontrol *kcontrol, | 719 | static int class_w_put_double(struct snd_kcontrol *kcontrol, |
722 | struct snd_ctl_elem_value *ucontrol) | 720 | struct snd_ctl_elem_value *ucontrol) |
723 | { | 721 | { |
724 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 722 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
725 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
726 | struct snd_soc_codec *codec = widget->codec; | ||
727 | int ret; | 723 | int ret; |
728 | 724 | ||
729 | ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); | 725 | ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 105f7c4bef81..7e9afbc49ef2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -47,6 +47,15 @@ | |||
47 | 47 | ||
48 | #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++; | 48 | #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++; |
49 | 49 | ||
50 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | ||
51 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, | ||
52 | const char *control, | ||
53 | int (*connected)(struct snd_soc_dapm_widget *source, | ||
54 | struct snd_soc_dapm_widget *sink)); | ||
55 | static struct snd_soc_dapm_widget * | ||
56 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | ||
57 | const struct snd_soc_dapm_widget *widget); | ||
58 | |||
50 | /* dapm power sequences - make this per codec in the future */ | 59 | /* dapm power sequences - make this per codec in the future */ |
51 | static int dapm_up_seq[] = { | 60 | static int dapm_up_seq[] = { |
52 | [snd_soc_dapm_pre] = 0, | 61 | [snd_soc_dapm_pre] = 0, |
@@ -73,16 +82,18 @@ static int dapm_up_seq[] = { | |||
73 | [snd_soc_dapm_hp] = 10, | 82 | [snd_soc_dapm_hp] = 10, |
74 | [snd_soc_dapm_spk] = 10, | 83 | [snd_soc_dapm_spk] = 10, |
75 | [snd_soc_dapm_line] = 10, | 84 | [snd_soc_dapm_line] = 10, |
76 | [snd_soc_dapm_post] = 11, | 85 | [snd_soc_dapm_kcontrol] = 11, |
86 | [snd_soc_dapm_post] = 12, | ||
77 | }; | 87 | }; |
78 | 88 | ||
79 | static int dapm_down_seq[] = { | 89 | static int dapm_down_seq[] = { |
80 | [snd_soc_dapm_pre] = 0, | 90 | [snd_soc_dapm_pre] = 0, |
81 | [snd_soc_dapm_adc] = 1, | 91 | [snd_soc_dapm_kcontrol] = 1, |
82 | [snd_soc_dapm_hp] = 2, | 92 | [snd_soc_dapm_adc] = 2, |
83 | [snd_soc_dapm_spk] = 2, | 93 | [snd_soc_dapm_hp] = 3, |
84 | [snd_soc_dapm_line] = 2, | 94 | [snd_soc_dapm_spk] = 3, |
85 | [snd_soc_dapm_out_drv] = 2, | 95 | [snd_soc_dapm_line] = 3, |
96 | [snd_soc_dapm_out_drv] = 3, | ||
86 | [snd_soc_dapm_pga] = 4, | 97 | [snd_soc_dapm_pga] = 4, |
87 | [snd_soc_dapm_switch] = 5, | 98 | [snd_soc_dapm_switch] = 5, |
88 | [snd_soc_dapm_mixer_named_ctl] = 5, | 99 | [snd_soc_dapm_mixer_named_ctl] = 5, |
@@ -174,6 +185,176 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | |||
174 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); | 185 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); |
175 | } | 186 | } |
176 | 187 | ||
188 | struct dapm_kcontrol_data { | ||
189 | unsigned int value; | ||
190 | struct snd_soc_dapm_widget *widget; | ||
191 | struct list_head paths; | ||
192 | struct snd_soc_dapm_widget_list *wlist; | ||
193 | }; | ||
194 | |||
195 | static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, | ||
196 | struct snd_kcontrol *kcontrol) | ||
197 | { | ||
198 | struct dapm_kcontrol_data *data; | ||
199 | struct soc_mixer_control *mc; | ||
200 | |||
201 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
202 | if (!data) { | ||
203 | dev_err(widget->dapm->dev, | ||
204 | "ASoC: can't allocate kcontrol data for %s\n", | ||
205 | widget->name); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | INIT_LIST_HEAD(&data->paths); | ||
210 | |||
211 | switch (widget->id) { | ||
212 | case snd_soc_dapm_switch: | ||
213 | case snd_soc_dapm_mixer: | ||
214 | case snd_soc_dapm_mixer_named_ctl: | ||
215 | mc = (struct soc_mixer_control *)kcontrol->private_value; | ||
216 | |||
217 | if (mc->autodisable) { | ||
218 | struct snd_soc_dapm_widget template; | ||
219 | |||
220 | memset(&template, 0, sizeof(template)); | ||
221 | template.reg = mc->reg; | ||
222 | template.mask = (1 << fls(mc->max)) - 1; | ||
223 | template.shift = mc->shift; | ||
224 | if (mc->invert) | ||
225 | template.off_val = mc->max; | ||
226 | else | ||
227 | template.off_val = 0; | ||
228 | template.on_val = template.off_val; | ||
229 | template.id = snd_soc_dapm_kcontrol; | ||
230 | template.name = kcontrol->id.name; | ||
231 | |||
232 | data->widget = snd_soc_dapm_new_control(widget->dapm, | ||
233 | &template); | ||
234 | if (!data->widget) { | ||
235 | kfree(data); | ||
236 | return -ENOMEM; | ||
237 | } | ||
238 | } | ||
239 | break; | ||
240 | default: | ||
241 | break; | ||
242 | } | ||
243 | |||
244 | kcontrol->private_data = data; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static void dapm_kcontrol_free(struct snd_kcontrol *kctl) | ||
250 | { | ||
251 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); | ||
252 | kfree(data->widget); | ||
253 | kfree(data->wlist); | ||
254 | kfree(data); | ||
255 | } | ||
256 | |||
257 | static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist( | ||
258 | const struct snd_kcontrol *kcontrol) | ||
259 | { | ||
260 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
261 | |||
262 | return data->wlist; | ||
263 | } | ||
264 | |||
265 | static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol, | ||
266 | struct snd_soc_dapm_widget *widget) | ||
267 | { | ||
268 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
269 | struct snd_soc_dapm_widget_list *new_wlist; | ||
270 | unsigned int n; | ||
271 | |||
272 | if (data->wlist) | ||
273 | n = data->wlist->num_widgets + 1; | ||
274 | else | ||
275 | n = 1; | ||
276 | |||
277 | new_wlist = krealloc(data->wlist, | ||
278 | sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL); | ||
279 | if (!new_wlist) | ||
280 | return -ENOMEM; | ||
281 | |||
282 | new_wlist->widgets[n - 1] = widget; | ||
283 | new_wlist->num_widgets = n; | ||
284 | |||
285 | data->wlist = new_wlist; | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol, | ||
291 | struct snd_soc_dapm_path *path) | ||
292 | { | ||
293 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
294 | |||
295 | list_add_tail(&path->list_kcontrol, &data->paths); | ||
296 | |||
297 | if (data->widget) { | ||
298 | snd_soc_dapm_add_path(data->widget->dapm, data->widget, | ||
299 | path->source, NULL, NULL); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol) | ||
304 | { | ||
305 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
306 | |||
307 | if (!data->widget) | ||
308 | return true; | ||
309 | |||
310 | return data->widget->power; | ||
311 | } | ||
312 | |||
313 | static struct list_head *dapm_kcontrol_get_path_list( | ||
314 | const struct snd_kcontrol *kcontrol) | ||
315 | { | ||
316 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
317 | |||
318 | return &data->paths; | ||
319 | } | ||
320 | |||
321 | #define dapm_kcontrol_for_each_path(path, kcontrol) \ | ||
322 | list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ | ||
323 | list_kcontrol) | ||
324 | |||
325 | static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) | ||
326 | { | ||
327 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
328 | |||
329 | return data->value; | ||
330 | } | ||
331 | |||
332 | static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, | ||
333 | unsigned int value) | ||
334 | { | ||
335 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | ||
336 | |||
337 | if (data->value == value) | ||
338 | return false; | ||
339 | |||
340 | if (data->widget) | ||
341 | data->widget->on_val = value; | ||
342 | |||
343 | data->value = value; | ||
344 | |||
345 | return true; | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol | ||
350 | * @kcontrol: The kcontrol | ||
351 | */ | ||
352 | struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) | ||
353 | { | ||
354 | return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec; | ||
355 | } | ||
356 | EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec); | ||
357 | |||
177 | static void dapm_reset(struct snd_soc_card *card) | 358 | static void dapm_reset(struct snd_soc_card *card) |
178 | { | 359 | { |
179 | struct snd_soc_dapm_widget *w; | 360 | struct snd_soc_dapm_widget *w; |
@@ -181,6 +362,7 @@ static void dapm_reset(struct snd_soc_card *card) | |||
181 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | 362 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); |
182 | 363 | ||
183 | list_for_each_entry(w, &card->widgets, list) { | 364 | list_for_each_entry(w, &card->widgets, list) { |
365 | w->new_power = w->power; | ||
184 | w->power_checked = false; | 366 | w->power_checked = false; |
185 | w->inputs = -1; | 367 | w->inputs = -1; |
186 | w->outputs = -1; | 368 | w->outputs = -1; |
@@ -398,6 +580,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
398 | case snd_soc_dapm_spk: | 580 | case snd_soc_dapm_spk: |
399 | case snd_soc_dapm_line: | 581 | case snd_soc_dapm_line: |
400 | case snd_soc_dapm_dai_link: | 582 | case snd_soc_dapm_dai_link: |
583 | case snd_soc_dapm_kcontrol: | ||
401 | p->connect = 1; | 584 | p->connect = 1; |
402 | break; | 585 | break; |
403 | /* does affect routing - dynamically connected */ | 586 | /* does affect routing - dynamically connected */ |
@@ -477,17 +660,12 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, | |||
477 | return 0; | 660 | return 0; |
478 | } | 661 | } |
479 | 662 | ||
480 | static void dapm_kcontrol_free(struct snd_kcontrol *kctl) | ||
481 | { | ||
482 | kfree(kctl->private_data); | ||
483 | } | ||
484 | |||
485 | /* | 663 | /* |
486 | * Determine if a kcontrol is shared. If it is, look it up. If it isn't, | 664 | * Determine if a kcontrol is shared. If it is, look it up. If it isn't, |
487 | * create it. Either way, add the widget into the control's widget list | 665 | * create it. Either way, add the widget into the control's widget list |
488 | */ | 666 | */ |
489 | static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | 667 | static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, |
490 | int kci, struct snd_soc_dapm_path *path) | 668 | int kci) |
491 | { | 669 | { |
492 | struct snd_soc_dapm_context *dapm = w->dapm; | 670 | struct snd_soc_dapm_context *dapm = w->dapm; |
493 | struct snd_card *card = dapm->card->snd_card; | 671 | struct snd_card *card = dapm->card->snd_card; |
@@ -495,9 +673,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
495 | size_t prefix_len; | 673 | size_t prefix_len; |
496 | int shared; | 674 | int shared; |
497 | struct snd_kcontrol *kcontrol; | 675 | struct snd_kcontrol *kcontrol; |
498 | struct snd_soc_dapm_widget_list *wlist; | ||
499 | int wlistentries; | ||
500 | size_t wlistsize; | ||
501 | bool wname_in_long_name, kcname_in_long_name; | 676 | bool wname_in_long_name, kcname_in_long_name; |
502 | char *long_name; | 677 | char *long_name; |
503 | const char *name; | 678 | const char *name; |
@@ -516,25 +691,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
516 | shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], | 691 | shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], |
517 | &kcontrol); | 692 | &kcontrol); |
518 | 693 | ||
519 | if (kcontrol) { | ||
520 | wlist = kcontrol->private_data; | ||
521 | wlistentries = wlist->num_widgets + 1; | ||
522 | } else { | ||
523 | wlist = NULL; | ||
524 | wlistentries = 1; | ||
525 | } | ||
526 | |||
527 | wlistsize = sizeof(struct snd_soc_dapm_widget_list) + | ||
528 | wlistentries * sizeof(struct snd_soc_dapm_widget *); | ||
529 | wlist = krealloc(wlist, wlistsize, GFP_KERNEL); | ||
530 | if (wlist == NULL) { | ||
531 | dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n", | ||
532 | w->name); | ||
533 | return -ENOMEM; | ||
534 | } | ||
535 | wlist->num_widgets = wlistentries; | ||
536 | wlist->widgets[wlistentries - 1] = w; | ||
537 | |||
538 | if (!kcontrol) { | 694 | if (!kcontrol) { |
539 | if (shared) { | 695 | if (shared) { |
540 | wname_in_long_name = false; | 696 | wname_in_long_name = false; |
@@ -557,7 +713,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
557 | kcname_in_long_name = false; | 713 | kcname_in_long_name = false; |
558 | break; | 714 | break; |
559 | default: | 715 | default: |
560 | kfree(wlist); | ||
561 | return -EINVAL; | 716 | return -EINVAL; |
562 | } | 717 | } |
563 | } | 718 | } |
@@ -572,10 +727,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
572 | long_name = kasprintf(GFP_KERNEL, "%s %s", | 727 | long_name = kasprintf(GFP_KERNEL, "%s %s", |
573 | w->name + prefix_len, | 728 | w->name + prefix_len, |
574 | w->kcontrol_news[kci].name); | 729 | w->kcontrol_news[kci].name); |
575 | if (long_name == NULL) { | 730 | if (long_name == NULL) |
576 | kfree(wlist); | ||
577 | return -ENOMEM; | 731 | return -ENOMEM; |
578 | } | ||
579 | 732 | ||
580 | name = long_name; | 733 | name = long_name; |
581 | } else if (wname_in_long_name) { | 734 | } else if (wname_in_long_name) { |
@@ -586,23 +739,33 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
586 | name = w->kcontrol_news[kci].name; | 739 | name = w->kcontrol_news[kci].name; |
587 | } | 740 | } |
588 | 741 | ||
589 | kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name, | 742 | kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name, |
590 | prefix); | 743 | prefix); |
591 | kcontrol->private_free = dapm_kcontrol_free; | ||
592 | kfree(long_name); | 744 | kfree(long_name); |
745 | if (!kcontrol) | ||
746 | return -ENOMEM; | ||
747 | kcontrol->private_free = dapm_kcontrol_free; | ||
748 | |||
749 | ret = dapm_kcontrol_data_alloc(w, kcontrol); | ||
750 | if (ret) { | ||
751 | snd_ctl_free_one(kcontrol); | ||
752 | return ret; | ||
753 | } | ||
754 | |||
593 | ret = snd_ctl_add(card, kcontrol); | 755 | ret = snd_ctl_add(card, kcontrol); |
594 | if (ret < 0) { | 756 | if (ret < 0) { |
595 | dev_err(dapm->dev, | 757 | dev_err(dapm->dev, |
596 | "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", | 758 | "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", |
597 | w->name, name, ret); | 759 | w->name, name, ret); |
598 | kfree(wlist); | ||
599 | return ret; | 760 | return ret; |
600 | } | 761 | } |
601 | } | 762 | } |
602 | 763 | ||
603 | kcontrol->private_data = wlist; | 764 | ret = dapm_kcontrol_add_widget(kcontrol, w); |
765 | if (ret) | ||
766 | return ret; | ||
767 | |||
604 | w->kcontrols[kci] = kcontrol; | 768 | w->kcontrols[kci] = kcontrol; |
605 | path->kcontrol = kcontrol; | ||
606 | 769 | ||
607 | return 0; | 770 | return 0; |
608 | } | 771 | } |
@@ -622,13 +785,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) | |||
622 | continue; | 785 | continue; |
623 | 786 | ||
624 | if (w->kcontrols[i]) { | 787 | if (w->kcontrols[i]) { |
625 | path->kcontrol = w->kcontrols[i]; | 788 | dapm_kcontrol_add_path(w->kcontrols[i], path); |
626 | continue; | 789 | continue; |
627 | } | 790 | } |
628 | 791 | ||
629 | ret = dapm_create_or_share_mixmux_kcontrol(w, i, path); | 792 | ret = dapm_create_or_share_mixmux_kcontrol(w, i); |
630 | if (ret < 0) | 793 | if (ret < 0) |
631 | return ret; | 794 | return ret; |
795 | |||
796 | dapm_kcontrol_add_path(w->kcontrols[i], path); | ||
632 | } | 797 | } |
633 | } | 798 | } |
634 | 799 | ||
@@ -654,15 +819,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
654 | return -EINVAL; | 819 | return -EINVAL; |
655 | } | 820 | } |
656 | 821 | ||
657 | path = list_first_entry(&w->sources, struct snd_soc_dapm_path, | 822 | ret = dapm_create_or_share_mixmux_kcontrol(w, 0); |
658 | list_sink); | ||
659 | |||
660 | ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path); | ||
661 | if (ret < 0) | 823 | if (ret < 0) |
662 | return ret; | 824 | return ret; |
663 | 825 | ||
664 | list_for_each_entry(path, &w->sources, list_sink) | 826 | list_for_each_entry(path, &w->sources, list_sink) |
665 | path->kcontrol = w->kcontrols[0]; | 827 | dapm_kcontrol_add_path(w->kcontrols[0], path); |
666 | 828 | ||
667 | return 0; | 829 | return 0; |
668 | } | 830 | } |
@@ -783,6 +945,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | |||
783 | case snd_soc_dapm_supply: | 945 | case snd_soc_dapm_supply: |
784 | case snd_soc_dapm_regulator_supply: | 946 | case snd_soc_dapm_regulator_supply: |
785 | case snd_soc_dapm_clock_supply: | 947 | case snd_soc_dapm_clock_supply: |
948 | case snd_soc_dapm_kcontrol: | ||
786 | return 0; | 949 | return 0; |
787 | default: | 950 | default: |
788 | break; | 951 | break; |
@@ -878,6 +1041,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
878 | case snd_soc_dapm_supply: | 1041 | case snd_soc_dapm_supply: |
879 | case snd_soc_dapm_regulator_supply: | 1042 | case snd_soc_dapm_regulator_supply: |
880 | case snd_soc_dapm_clock_supply: | 1043 | case snd_soc_dapm_clock_supply: |
1044 | case snd_soc_dapm_kcontrol: | ||
881 | return 0; | 1045 | return 0; |
882 | default: | 1046 | default: |
883 | break; | 1047 | break; |
@@ -1032,7 +1196,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1032 | int ret; | 1196 | int ret; |
1033 | 1197 | ||
1034 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 1198 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
1035 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 1199 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
1036 | ret = regulator_allow_bypass(w->regulator, false); | 1200 | ret = regulator_allow_bypass(w->regulator, false); |
1037 | if (ret != 0) | 1201 | if (ret != 0) |
1038 | dev_warn(w->dapm->dev, | 1202 | dev_warn(w->dapm->dev, |
@@ -1042,7 +1206,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1042 | 1206 | ||
1043 | return regulator_enable(w->regulator); | 1207 | return regulator_enable(w->regulator); |
1044 | } else { | 1208 | } else { |
1045 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 1209 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
1046 | ret = regulator_allow_bypass(w->regulator, true); | 1210 | ret = regulator_allow_bypass(w->regulator, true); |
1047 | if (ret != 0) | 1211 | if (ret != 0) |
1048 | dev_warn(w->dapm->dev, | 1212 | dev_warn(w->dapm->dev, |
@@ -1214,10 +1378,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, | |||
1214 | list_add_tail(&new_widget->power_list, list); | 1378 | list_add_tail(&new_widget->power_list, list); |
1215 | } | 1379 | } |
1216 | 1380 | ||
1217 | static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, | 1381 | static void dapm_seq_check_event(struct snd_soc_card *card, |
1218 | struct snd_soc_dapm_widget *w, int event) | 1382 | struct snd_soc_dapm_widget *w, int event) |
1219 | { | 1383 | { |
1220 | struct snd_soc_card *card = dapm->card; | ||
1221 | const char *ev_name; | 1384 | const char *ev_name; |
1222 | int power, ret; | 1385 | int power, ret; |
1223 | 1386 | ||
@@ -1251,55 +1414,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, | |||
1251 | return; | 1414 | return; |
1252 | } | 1415 | } |
1253 | 1416 | ||
1254 | if (w->power != power) | 1417 | if (w->new_power != power) |
1255 | return; | 1418 | return; |
1256 | 1419 | ||
1257 | if (w->event && (w->event_flags & event)) { | 1420 | if (w->event && (w->event_flags & event)) { |
1258 | pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n", | 1421 | pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n", |
1259 | w->name, ev_name); | 1422 | w->name, ev_name); |
1260 | trace_snd_soc_dapm_widget_event_start(w, event); | 1423 | trace_snd_soc_dapm_widget_event_start(w, event); |
1261 | ret = w->event(w, NULL, event); | 1424 | ret = w->event(w, NULL, event); |
1262 | trace_snd_soc_dapm_widget_event_done(w, event); | 1425 | trace_snd_soc_dapm_widget_event_done(w, event); |
1263 | if (ret < 0) | 1426 | if (ret < 0) |
1264 | dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n", | 1427 | dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n", |
1265 | ev_name, w->name, ret); | 1428 | ev_name, w->name, ret); |
1266 | } | 1429 | } |
1267 | } | 1430 | } |
1268 | 1431 | ||
1269 | /* Apply the coalesced changes from a DAPM sequence */ | 1432 | /* Apply the coalesced changes from a DAPM sequence */ |
1270 | static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | 1433 | static void dapm_seq_run_coalesced(struct snd_soc_card *card, |
1271 | struct list_head *pending) | 1434 | struct list_head *pending) |
1272 | { | 1435 | { |
1273 | struct snd_soc_card *card = dapm->card; | ||
1274 | struct snd_soc_dapm_widget *w; | 1436 | struct snd_soc_dapm_widget *w; |
1275 | int reg, power; | 1437 | int reg; |
1276 | unsigned int value = 0; | 1438 | unsigned int value = 0; |
1277 | unsigned int mask = 0; | 1439 | unsigned int mask = 0; |
1278 | unsigned int cur_mask; | ||
1279 | 1440 | ||
1280 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, | 1441 | reg = list_first_entry(pending, struct snd_soc_dapm_widget, |
1281 | power_list)->reg; | 1442 | power_list)->reg; |
1282 | 1443 | ||
1283 | list_for_each_entry(w, pending, power_list) { | 1444 | list_for_each_entry(w, pending, power_list) { |
1284 | cur_mask = 1 << w->shift; | ||
1285 | BUG_ON(reg != w->reg); | 1445 | BUG_ON(reg != w->reg); |
1446 | w->power = w->new_power; | ||
1286 | 1447 | ||
1287 | if (w->invert) | 1448 | mask |= w->mask << w->shift; |
1288 | power = !w->power; | 1449 | if (w->power) |
1450 | value |= w->on_val << w->shift; | ||
1289 | else | 1451 | else |
1290 | power = w->power; | 1452 | value |= w->off_val << w->shift; |
1291 | |||
1292 | mask |= cur_mask; | ||
1293 | if (power) | ||
1294 | value |= cur_mask; | ||
1295 | 1453 | ||
1296 | pop_dbg(dapm->dev, card->pop_time, | 1454 | pop_dbg(w->dapm->dev, card->pop_time, |
1297 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", | 1455 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", |
1298 | w->name, reg, value, mask); | 1456 | w->name, reg, value, mask); |
1299 | 1457 | ||
1300 | /* Check for events */ | 1458 | /* Check for events */ |
1301 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU); | 1459 | dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU); |
1302 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD); | 1460 | dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD); |
1303 | } | 1461 | } |
1304 | 1462 | ||
1305 | if (reg >= 0) { | 1463 | if (reg >= 0) { |
@@ -1309,7 +1467,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1309 | w = list_first_entry(pending, struct snd_soc_dapm_widget, | 1467 | w = list_first_entry(pending, struct snd_soc_dapm_widget, |
1310 | power_list); | 1468 | power_list); |
1311 | 1469 | ||
1312 | pop_dbg(dapm->dev, card->pop_time, | 1470 | pop_dbg(w->dapm->dev, card->pop_time, |
1313 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 1471 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
1314 | value, mask, reg, card->pop_time); | 1472 | value, mask, reg, card->pop_time); |
1315 | pop_wait(card->pop_time); | 1473 | pop_wait(card->pop_time); |
@@ -1317,8 +1475,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1317 | } | 1475 | } |
1318 | 1476 | ||
1319 | list_for_each_entry(w, pending, power_list) { | 1477 | list_for_each_entry(w, pending, power_list) { |
1320 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU); | 1478 | dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU); |
1321 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD); | 1479 | dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD); |
1322 | } | 1480 | } |
1323 | } | 1481 | } |
1324 | 1482 | ||
@@ -1330,8 +1488,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1330 | * Currently anything that requires more than a single write is not | 1488 | * Currently anything that requires more than a single write is not |
1331 | * handled. | 1489 | * handled. |
1332 | */ | 1490 | */ |
1333 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | 1491 | static void dapm_seq_run(struct snd_soc_card *card, |
1334 | struct list_head *list, int event, bool power_up) | 1492 | struct list_head *list, int event, bool power_up) |
1335 | { | 1493 | { |
1336 | struct snd_soc_dapm_widget *w, *n; | 1494 | struct snd_soc_dapm_widget *w, *n; |
1337 | LIST_HEAD(pending); | 1495 | LIST_HEAD(pending); |
@@ -1354,7 +1512,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1354 | if (sort[w->id] != cur_sort || w->reg != cur_reg || | 1512 | if (sort[w->id] != cur_sort || w->reg != cur_reg || |
1355 | w->dapm != cur_dapm || w->subseq != cur_subseq) { | 1513 | w->dapm != cur_dapm || w->subseq != cur_subseq) { |
1356 | if (!list_empty(&pending)) | 1514 | if (!list_empty(&pending)) |
1357 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1515 | dapm_seq_run_coalesced(card, &pending); |
1358 | 1516 | ||
1359 | if (cur_dapm && cur_dapm->seq_notifier) { | 1517 | if (cur_dapm && cur_dapm->seq_notifier) { |
1360 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | 1518 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
@@ -1414,7 +1572,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1414 | } | 1572 | } |
1415 | 1573 | ||
1416 | if (!list_empty(&pending)) | 1574 | if (!list_empty(&pending)) |
1417 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1575 | dapm_seq_run_coalesced(card, &pending); |
1418 | 1576 | ||
1419 | if (cur_dapm && cur_dapm->seq_notifier) { | 1577 | if (cur_dapm && cur_dapm->seq_notifier) { |
1420 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | 1578 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
@@ -1424,37 +1582,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
1424 | } | 1582 | } |
1425 | } | 1583 | } |
1426 | 1584 | ||
1427 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | 1585 | static void dapm_widget_update(struct snd_soc_card *card) |
1428 | { | 1586 | { |
1429 | struct snd_soc_dapm_update *update = dapm->update; | 1587 | struct snd_soc_dapm_update *update = card->update; |
1430 | struct snd_soc_dapm_widget *w; | 1588 | struct snd_soc_dapm_widget_list *wlist; |
1589 | struct snd_soc_dapm_widget *w = NULL; | ||
1590 | unsigned int wi; | ||
1431 | int ret; | 1591 | int ret; |
1432 | 1592 | ||
1433 | if (!update) | 1593 | if (!update || !dapm_kcontrol_is_powered(update->kcontrol)) |
1434 | return; | 1594 | return; |
1435 | 1595 | ||
1436 | w = update->widget; | 1596 | wlist = dapm_kcontrol_get_wlist(update->kcontrol); |
1437 | 1597 | ||
1438 | if (w->event && | 1598 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
1439 | (w->event_flags & SND_SOC_DAPM_PRE_REG)) { | 1599 | w = wlist->widgets[wi]; |
1440 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); | 1600 | |
1441 | if (ret != 0) | 1601 | if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) { |
1442 | dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", | 1602 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); |
1443 | w->name, ret); | 1603 | if (ret != 0) |
1604 | dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", | ||
1605 | w->name, ret); | ||
1606 | } | ||
1444 | } | 1607 | } |
1445 | 1608 | ||
1609 | if (!w) | ||
1610 | return; | ||
1611 | |||
1446 | ret = soc_widget_update_bits_locked(w, update->reg, update->mask, | 1612 | ret = soc_widget_update_bits_locked(w, update->reg, update->mask, |
1447 | update->val); | 1613 | update->val); |
1448 | if (ret < 0) | 1614 | if (ret < 0) |
1449 | dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n", | 1615 | dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", |
1450 | w->name, ret); | 1616 | w->name, ret); |
1451 | 1617 | ||
1452 | if (w->event && | 1618 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
1453 | (w->event_flags & SND_SOC_DAPM_POST_REG)) { | 1619 | w = wlist->widgets[wi]; |
1454 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); | 1620 | |
1455 | if (ret != 0) | 1621 | if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) { |
1456 | dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", | 1622 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); |
1457 | w->name, ret); | 1623 | if (ret != 0) |
1624 | dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", | ||
1625 | w->name, ret); | ||
1626 | } | ||
1458 | } | 1627 | } |
1459 | } | 1628 | } |
1460 | 1629 | ||
@@ -1566,6 +1735,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1566 | case snd_soc_dapm_supply: | 1735 | case snd_soc_dapm_supply: |
1567 | case snd_soc_dapm_regulator_supply: | 1736 | case snd_soc_dapm_regulator_supply: |
1568 | case snd_soc_dapm_clock_supply: | 1737 | case snd_soc_dapm_clock_supply: |
1738 | case snd_soc_dapm_kcontrol: | ||
1569 | /* Supplies can't affect their outputs, only their inputs */ | 1739 | /* Supplies can't affect their outputs, only their inputs */ |
1570 | break; | 1740 | break; |
1571 | default: | 1741 | default: |
@@ -1582,8 +1752,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1582 | dapm_seq_insert(w, up_list, true); | 1752 | dapm_seq_insert(w, up_list, true); |
1583 | else | 1753 | else |
1584 | dapm_seq_insert(w, down_list, false); | 1754 | dapm_seq_insert(w, down_list, false); |
1585 | |||
1586 | w->power = power; | ||
1587 | } | 1755 | } |
1588 | 1756 | ||
1589 | static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, | 1757 | static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, |
@@ -1617,9 +1785,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, | |||
1617 | * o Input pin to Output pin (bypass, sidetone) | 1785 | * o Input pin to Output pin (bypass, sidetone) |
1618 | * o DAC to ADC (loopback). | 1786 | * o DAC to ADC (loopback). |
1619 | */ | 1787 | */ |
1620 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | 1788 | static int dapm_power_widgets(struct snd_soc_card *card, int event) |
1621 | { | 1789 | { |
1622 | struct snd_soc_card *card = dapm->card; | ||
1623 | struct snd_soc_dapm_widget *w; | 1790 | struct snd_soc_dapm_widget *w; |
1624 | struct snd_soc_dapm_context *d; | 1791 | struct snd_soc_dapm_context *d; |
1625 | LIST_HEAD(up_list); | 1792 | LIST_HEAD(up_list); |
@@ -1659,7 +1826,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1659 | break; | 1826 | break; |
1660 | } | 1827 | } |
1661 | 1828 | ||
1662 | if (w->power) { | 1829 | if (w->new_power) { |
1663 | d = w->dapm; | 1830 | d = w->dapm; |
1664 | 1831 | ||
1665 | /* Supplies and micbiases only bring the | 1832 | /* Supplies and micbiases only bring the |
@@ -1701,29 +1868,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1701 | trace_snd_soc_dapm_walk_done(card); | 1868 | trace_snd_soc_dapm_walk_done(card); |
1702 | 1869 | ||
1703 | /* Run all the bias changes in parallel */ | 1870 | /* Run all the bias changes in parallel */ |
1704 | list_for_each_entry(d, &dapm->card->dapm_list, list) | 1871 | list_for_each_entry(d, &card->dapm_list, list) |
1705 | async_schedule_domain(dapm_pre_sequence_async, d, | 1872 | async_schedule_domain(dapm_pre_sequence_async, d, |
1706 | &async_domain); | 1873 | &async_domain); |
1707 | async_synchronize_full_domain(&async_domain); | 1874 | async_synchronize_full_domain(&async_domain); |
1708 | 1875 | ||
1709 | list_for_each_entry(w, &down_list, power_list) { | 1876 | list_for_each_entry(w, &down_list, power_list) { |
1710 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD); | 1877 | dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD); |
1711 | } | 1878 | } |
1712 | 1879 | ||
1713 | list_for_each_entry(w, &up_list, power_list) { | 1880 | list_for_each_entry(w, &up_list, power_list) { |
1714 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU); | 1881 | dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU); |
1715 | } | 1882 | } |
1716 | 1883 | ||
1717 | /* Power down widgets first; try to avoid amplifying pops. */ | 1884 | /* Power down widgets first; try to avoid amplifying pops. */ |
1718 | dapm_seq_run(dapm, &down_list, event, false); | 1885 | dapm_seq_run(card, &down_list, event, false); |
1719 | 1886 | ||
1720 | dapm_widget_update(dapm); | 1887 | dapm_widget_update(card); |
1721 | 1888 | ||
1722 | /* Now power up. */ | 1889 | /* Now power up. */ |
1723 | dapm_seq_run(dapm, &up_list, event, true); | 1890 | dapm_seq_run(card, &up_list, event, true); |
1724 | 1891 | ||
1725 | /* Run all the bias changes in parallel */ | 1892 | /* Run all the bias changes in parallel */ |
1726 | list_for_each_entry(d, &dapm->card->dapm_list, list) | 1893 | list_for_each_entry(d, &card->dapm_list, list) |
1727 | async_schedule_domain(dapm_post_sequence_async, d, | 1894 | async_schedule_domain(dapm_post_sequence_async, d, |
1728 | &async_domain); | 1895 | &async_domain); |
1729 | async_synchronize_full_domain(&async_domain); | 1896 | async_synchronize_full_domain(&async_domain); |
@@ -1734,7 +1901,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1734 | d->stream_event(d, event); | 1901 | d->stream_event(d, event); |
1735 | } | 1902 | } |
1736 | 1903 | ||
1737 | pop_dbg(dapm->dev, card->pop_time, | 1904 | pop_dbg(card->dev, card->pop_time, |
1738 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); | 1905 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
1739 | pop_wait(card->pop_time); | 1906 | pop_wait(card->pop_time); |
1740 | 1907 | ||
@@ -1769,8 +1936,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1769 | 1936 | ||
1770 | if (w->reg >= 0) | 1937 | if (w->reg >= 0) |
1771 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1938 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1772 | " - R%d(0x%x) bit %d", | 1939 | " - R%d(0x%x) mask 0x%x", |
1773 | w->reg, w->reg, w->shift); | 1940 | w->reg, w->reg, w->mask << w->shift); |
1774 | 1941 | ||
1775 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); | 1942 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); |
1776 | 1943 | ||
@@ -1907,22 +2074,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
1907 | #endif | 2074 | #endif |
1908 | 2075 | ||
1909 | /* test and update the power status of a mux widget */ | 2076 | /* test and update the power status of a mux widget */ |
1910 | static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 2077 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, |
1911 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 2078 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
1912 | { | 2079 | { |
1913 | struct snd_soc_dapm_path *path; | 2080 | struct snd_soc_dapm_path *path; |
1914 | int found = 0; | 2081 | int found = 0; |
1915 | 2082 | ||
1916 | if (widget->id != snd_soc_dapm_mux && | ||
1917 | widget->id != snd_soc_dapm_virt_mux && | ||
1918 | widget->id != snd_soc_dapm_value_mux) | ||
1919 | return -ENODEV; | ||
1920 | |||
1921 | /* find dapm widget path assoc with kcontrol */ | 2083 | /* find dapm widget path assoc with kcontrol */ |
1922 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 2084 | dapm_kcontrol_for_each_path(path, kcontrol) { |
1923 | if (path->kcontrol != kcontrol) | ||
1924 | continue; | ||
1925 | |||
1926 | if (!path->name || !e->texts[mux]) | 2085 | if (!path->name || !e->texts[mux]) |
1927 | continue; | 2086 | continue; |
1928 | 2087 | ||
@@ -1937,73 +2096,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1937 | "mux disconnection"); | 2096 | "mux disconnection"); |
1938 | path->connect = 0; /* old connection must be powered down */ | 2097 | path->connect = 0; /* old connection must be powered down */ |
1939 | } | 2098 | } |
2099 | dapm_mark_dirty(path->sink, "mux change"); | ||
1940 | } | 2100 | } |
1941 | 2101 | ||
1942 | if (found) { | 2102 | if (found) |
1943 | dapm_mark_dirty(widget, "mux change"); | 2103 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
1944 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | ||
1945 | } | ||
1946 | 2104 | ||
1947 | return found; | 2105 | return found; |
1948 | } | 2106 | } |
1949 | 2107 | ||
1950 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 2108 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, |
1951 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 2109 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e, |
2110 | struct snd_soc_dapm_update *update) | ||
1952 | { | 2111 | { |
1953 | struct snd_soc_card *card = widget->dapm->card; | 2112 | struct snd_soc_card *card = dapm->card; |
1954 | int ret; | 2113 | int ret; |
1955 | 2114 | ||
1956 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2115 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
1957 | ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 2116 | card->update = update; |
2117 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | ||
2118 | card->update = NULL; | ||
1958 | mutex_unlock(&card->dapm_mutex); | 2119 | mutex_unlock(&card->dapm_mutex); |
1959 | if (ret > 0) | 2120 | if (ret > 0) |
1960 | soc_dpcm_runtime_update(widget); | 2121 | soc_dpcm_runtime_update(card); |
1961 | return ret; | 2122 | return ret; |
1962 | } | 2123 | } |
1963 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); | 2124 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); |
1964 | 2125 | ||
1965 | /* test and update the power status of a mixer or switch widget */ | 2126 | /* test and update the power status of a mixer or switch widget */ |
1966 | static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 2127 | static int soc_dapm_mixer_update_power(struct snd_soc_card *card, |
1967 | struct snd_kcontrol *kcontrol, int connect) | 2128 | struct snd_kcontrol *kcontrol, int connect) |
1968 | { | 2129 | { |
1969 | struct snd_soc_dapm_path *path; | 2130 | struct snd_soc_dapm_path *path; |
1970 | int found = 0; | 2131 | int found = 0; |
1971 | 2132 | ||
1972 | if (widget->id != snd_soc_dapm_mixer && | ||
1973 | widget->id != snd_soc_dapm_mixer_named_ctl && | ||
1974 | widget->id != snd_soc_dapm_switch) | ||
1975 | return -ENODEV; | ||
1976 | |||
1977 | /* find dapm widget path assoc with kcontrol */ | 2133 | /* find dapm widget path assoc with kcontrol */ |
1978 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 2134 | dapm_kcontrol_for_each_path(path, kcontrol) { |
1979 | if (path->kcontrol != kcontrol) | ||
1980 | continue; | ||
1981 | |||
1982 | /* found, now check type */ | ||
1983 | found = 1; | 2135 | found = 1; |
1984 | path->connect = connect; | 2136 | path->connect = connect; |
1985 | dapm_mark_dirty(path->source, "mixer connection"); | 2137 | dapm_mark_dirty(path->source, "mixer connection"); |
2138 | dapm_mark_dirty(path->sink, "mixer update"); | ||
1986 | } | 2139 | } |
1987 | 2140 | ||
1988 | if (found) { | 2141 | if (found) |
1989 | dapm_mark_dirty(widget, "mixer update"); | 2142 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
1990 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | ||
1991 | } | ||
1992 | 2143 | ||
1993 | return found; | 2144 | return found; |
1994 | } | 2145 | } |
1995 | 2146 | ||
1996 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 2147 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, |
1997 | struct snd_kcontrol *kcontrol, int connect) | 2148 | struct snd_kcontrol *kcontrol, int connect, |
2149 | struct snd_soc_dapm_update *update) | ||
1998 | { | 2150 | { |
1999 | struct snd_soc_card *card = widget->dapm->card; | 2151 | struct snd_soc_card *card = dapm->card; |
2000 | int ret; | 2152 | int ret; |
2001 | 2153 | ||
2002 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2154 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2003 | ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); | 2155 | card->update = update; |
2156 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect); | ||
2157 | card->update = NULL; | ||
2004 | mutex_unlock(&card->dapm_mutex); | 2158 | mutex_unlock(&card->dapm_mutex); |
2005 | if (ret > 0) | 2159 | if (ret > 0) |
2006 | soc_dpcm_runtime_update(widget); | 2160 | soc_dpcm_runtime_update(card); |
2007 | return ret; | 2161 | return ret; |
2008 | } | 2162 | } |
2009 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | 2163 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); |
@@ -2082,6 +2236,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) | |||
2082 | { | 2236 | { |
2083 | list_del(&path->list_sink); | 2237 | list_del(&path->list_sink); |
2084 | list_del(&path->list_source); | 2238 | list_del(&path->list_source); |
2239 | list_del(&path->list_kcontrol); | ||
2085 | list_del(&path->list); | 2240 | list_del(&path->list); |
2086 | kfree(path); | 2241 | kfree(path); |
2087 | } | 2242 | } |
@@ -2176,70 +2331,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2176 | return 0; | 2331 | return 0; |
2177 | 2332 | ||
2178 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2333 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2179 | ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2334 | ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); |
2180 | mutex_unlock(&dapm->card->dapm_mutex); | 2335 | mutex_unlock(&dapm->card->dapm_mutex); |
2181 | return ret; | 2336 | return ret; |
2182 | } | 2337 | } |
2183 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 2338 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
2184 | 2339 | ||
2185 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | 2340 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
2186 | const struct snd_soc_dapm_route *route) | 2341 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
2342 | const char *control, | ||
2343 | int (*connected)(struct snd_soc_dapm_widget *source, | ||
2344 | struct snd_soc_dapm_widget *sink)) | ||
2187 | { | 2345 | { |
2188 | struct snd_soc_dapm_path *path; | 2346 | struct snd_soc_dapm_path *path; |
2189 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 2347 | int ret; |
2190 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; | ||
2191 | const char *sink; | ||
2192 | const char *control = route->control; | ||
2193 | const char *source; | ||
2194 | char prefixed_sink[80]; | ||
2195 | char prefixed_source[80]; | ||
2196 | int ret = 0; | ||
2197 | |||
2198 | if (dapm->codec && dapm->codec->name_prefix) { | ||
2199 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | ||
2200 | dapm->codec->name_prefix, route->sink); | ||
2201 | sink = prefixed_sink; | ||
2202 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | ||
2203 | dapm->codec->name_prefix, route->source); | ||
2204 | source = prefixed_source; | ||
2205 | } else { | ||
2206 | sink = route->sink; | ||
2207 | source = route->source; | ||
2208 | } | ||
2209 | |||
2210 | /* | ||
2211 | * find src and dest widgets over all widgets but favor a widget from | ||
2212 | * current DAPM context | ||
2213 | */ | ||
2214 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
2215 | if (!wsink && !(strcmp(w->name, sink))) { | ||
2216 | wtsink = w; | ||
2217 | if (w->dapm == dapm) | ||
2218 | wsink = w; | ||
2219 | continue; | ||
2220 | } | ||
2221 | if (!wsource && !(strcmp(w->name, source))) { | ||
2222 | wtsource = w; | ||
2223 | if (w->dapm == dapm) | ||
2224 | wsource = w; | ||
2225 | } | ||
2226 | } | ||
2227 | /* use widget from another DAPM context if not found from this */ | ||
2228 | if (!wsink) | ||
2229 | wsink = wtsink; | ||
2230 | if (!wsource) | ||
2231 | wsource = wtsource; | ||
2232 | |||
2233 | if (wsource == NULL) { | ||
2234 | dev_err(dapm->dev, "ASoC: no source widget found for %s\n", | ||
2235 | route->source); | ||
2236 | return -ENODEV; | ||
2237 | } | ||
2238 | if (wsink == NULL) { | ||
2239 | dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", | ||
2240 | route->sink); | ||
2241 | return -ENODEV; | ||
2242 | } | ||
2243 | 2348 | ||
2244 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2349 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
2245 | if (!path) | 2350 | if (!path) |
@@ -2247,8 +2352,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2247 | 2352 | ||
2248 | path->source = wsource; | 2353 | path->source = wsource; |
2249 | path->sink = wsink; | 2354 | path->sink = wsink; |
2250 | path->connected = route->connected; | 2355 | path->connected = connected; |
2251 | INIT_LIST_HEAD(&path->list); | 2356 | INIT_LIST_HEAD(&path->list); |
2357 | INIT_LIST_HEAD(&path->list_kcontrol); | ||
2252 | INIT_LIST_HEAD(&path->list_source); | 2358 | INIT_LIST_HEAD(&path->list_source); |
2253 | INIT_LIST_HEAD(&path->list_sink); | 2359 | INIT_LIST_HEAD(&path->list_sink); |
2254 | 2360 | ||
@@ -2268,6 +2374,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2268 | wsource->ext = 1; | 2374 | wsource->ext = 1; |
2269 | } | 2375 | } |
2270 | 2376 | ||
2377 | dapm_mark_dirty(wsource, "Route added"); | ||
2378 | dapm_mark_dirty(wsink, "Route added"); | ||
2379 | |||
2271 | /* connect static paths */ | 2380 | /* connect static paths */ |
2272 | if (control == NULL) { | 2381 | if (control == NULL) { |
2273 | list_add(&path->list, &dapm->card->paths); | 2382 | list_add(&path->list, &dapm->card->paths); |
@@ -2298,6 +2407,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2298 | case snd_soc_dapm_dai_in: | 2407 | case snd_soc_dapm_dai_in: |
2299 | case snd_soc_dapm_dai_out: | 2408 | case snd_soc_dapm_dai_out: |
2300 | case snd_soc_dapm_dai_link: | 2409 | case snd_soc_dapm_dai_link: |
2410 | case snd_soc_dapm_kcontrol: | ||
2301 | list_add(&path->list, &dapm->card->paths); | 2411 | list_add(&path->list, &dapm->card->paths); |
2302 | list_add(&path->list_sink, &wsink->sources); | 2412 | list_add(&path->list_sink, &wsink->sources); |
2303 | list_add(&path->list_source, &wsource->sinks); | 2413 | list_add(&path->list_source, &wsource->sinks); |
@@ -2329,15 +2439,78 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2329 | return 0; | 2439 | return 0; |
2330 | } | 2440 | } |
2331 | 2441 | ||
2332 | dapm_mark_dirty(wsource, "Route added"); | ||
2333 | dapm_mark_dirty(wsink, "Route added"); | ||
2334 | |||
2335 | return 0; | 2442 | return 0; |
2443 | err: | ||
2444 | kfree(path); | ||
2445 | return ret; | ||
2446 | } | ||
2447 | |||
2448 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | ||
2449 | const struct snd_soc_dapm_route *route) | ||
2450 | { | ||
2451 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | ||
2452 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; | ||
2453 | const char *sink; | ||
2454 | const char *source; | ||
2455 | char prefixed_sink[80]; | ||
2456 | char prefixed_source[80]; | ||
2457 | int ret; | ||
2458 | |||
2459 | if (dapm->codec && dapm->codec->name_prefix) { | ||
2460 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | ||
2461 | dapm->codec->name_prefix, route->sink); | ||
2462 | sink = prefixed_sink; | ||
2463 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | ||
2464 | dapm->codec->name_prefix, route->source); | ||
2465 | source = prefixed_source; | ||
2466 | } else { | ||
2467 | sink = route->sink; | ||
2468 | source = route->source; | ||
2469 | } | ||
2470 | |||
2471 | /* | ||
2472 | * find src and dest widgets over all widgets but favor a widget from | ||
2473 | * current DAPM context | ||
2474 | */ | ||
2475 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
2476 | if (!wsink && !(strcmp(w->name, sink))) { | ||
2477 | wtsink = w; | ||
2478 | if (w->dapm == dapm) | ||
2479 | wsink = w; | ||
2480 | continue; | ||
2481 | } | ||
2482 | if (!wsource && !(strcmp(w->name, source))) { | ||
2483 | wtsource = w; | ||
2484 | if (w->dapm == dapm) | ||
2485 | wsource = w; | ||
2486 | } | ||
2487 | } | ||
2488 | /* use widget from another DAPM context if not found from this */ | ||
2489 | if (!wsink) | ||
2490 | wsink = wtsink; | ||
2491 | if (!wsource) | ||
2492 | wsource = wtsource; | ||
2336 | 2493 | ||
2494 | if (wsource == NULL) { | ||
2495 | dev_err(dapm->dev, "ASoC: no source widget found for %s\n", | ||
2496 | route->source); | ||
2497 | return -ENODEV; | ||
2498 | } | ||
2499 | if (wsink == NULL) { | ||
2500 | dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", | ||
2501 | route->sink); | ||
2502 | return -ENODEV; | ||
2503 | } | ||
2504 | |||
2505 | ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control, | ||
2506 | route->connected); | ||
2507 | if (ret) | ||
2508 | goto err; | ||
2509 | |||
2510 | return 0; | ||
2337 | err: | 2511 | err: |
2338 | dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", | 2512 | dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", |
2339 | source, control, sink); | 2513 | source, route->control, sink); |
2340 | kfree(path); | ||
2341 | return ret; | 2514 | return ret; |
2342 | } | 2515 | } |
2343 | 2516 | ||
@@ -2541,12 +2714,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); | |||
2541 | */ | 2714 | */ |
2542 | int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | 2715 | int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) |
2543 | { | 2716 | { |
2717 | struct snd_soc_card *card = dapm->card; | ||
2544 | struct snd_soc_dapm_widget *w; | 2718 | struct snd_soc_dapm_widget *w; |
2545 | unsigned int val; | 2719 | unsigned int val; |
2546 | 2720 | ||
2547 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | 2721 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); |
2548 | 2722 | ||
2549 | list_for_each_entry(w, &dapm->card->widgets, list) | 2723 | list_for_each_entry(w, &card->widgets, list) |
2550 | { | 2724 | { |
2551 | if (w->new) | 2725 | if (w->new) |
2552 | continue; | 2726 | continue; |
@@ -2556,7 +2730,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2556 | sizeof(struct snd_kcontrol *), | 2730 | sizeof(struct snd_kcontrol *), |
2557 | GFP_KERNEL); | 2731 | GFP_KERNEL); |
2558 | if (!w->kcontrols) { | 2732 | if (!w->kcontrols) { |
2559 | mutex_unlock(&dapm->card->dapm_mutex); | 2733 | mutex_unlock(&card->dapm_mutex); |
2560 | return -ENOMEM; | 2734 | return -ENOMEM; |
2561 | } | 2735 | } |
2562 | } | 2736 | } |
@@ -2582,12 +2756,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2582 | 2756 | ||
2583 | /* Read the initial power state from the device */ | 2757 | /* Read the initial power state from the device */ |
2584 | if (w->reg >= 0) { | 2758 | if (w->reg >= 0) { |
2585 | val = soc_widget_read(w, w->reg); | 2759 | val = soc_widget_read(w, w->reg) >> w->shift; |
2586 | val &= 1 << w->shift; | 2760 | val &= w->mask; |
2587 | if (w->invert) | 2761 | if (val == w->on_val) |
2588 | val = !val; | ||
2589 | |||
2590 | if (val) | ||
2591 | w->power = 1; | 2762 | w->power = 1; |
2592 | } | 2763 | } |
2593 | 2764 | ||
@@ -2597,8 +2768,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2597 | dapm_debugfs_add_widget(w); | 2768 | dapm_debugfs_add_widget(w); |
2598 | } | 2769 | } |
2599 | 2770 | ||
2600 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2771 | dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); |
2601 | mutex_unlock(&dapm->card->dapm_mutex); | 2772 | mutex_unlock(&card->dapm_mutex); |
2602 | return 0; | 2773 | return 0; |
2603 | } | 2774 | } |
2604 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | 2775 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); |
@@ -2615,8 +2786,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
2615 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | 2786 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, |
2616 | struct snd_ctl_elem_value *ucontrol) | 2787 | struct snd_ctl_elem_value *ucontrol) |
2617 | { | 2788 | { |
2618 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2789 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2619 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | 2790 | struct snd_soc_card *card = codec->card; |
2620 | struct soc_mixer_control *mc = | 2791 | struct soc_mixer_control *mc = |
2621 | (struct soc_mixer_control *)kcontrol->private_value; | 2792 | (struct soc_mixer_control *)kcontrol->private_value; |
2622 | unsigned int reg = mc->reg; | 2793 | unsigned int reg = mc->reg; |
@@ -2624,17 +2795,24 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2624 | int max = mc->max; | 2795 | int max = mc->max; |
2625 | unsigned int mask = (1 << fls(max)) - 1; | 2796 | unsigned int mask = (1 << fls(max)) - 1; |
2626 | unsigned int invert = mc->invert; | 2797 | unsigned int invert = mc->invert; |
2798 | unsigned int val; | ||
2627 | 2799 | ||
2628 | if (snd_soc_volsw_is_stereo(mc)) | 2800 | if (snd_soc_volsw_is_stereo(mc)) |
2629 | dev_warn(widget->dapm->dev, | 2801 | dev_warn(codec->dapm.dev, |
2630 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2802 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2631 | kcontrol->id.name); | 2803 | kcontrol->id.name); |
2632 | 2804 | ||
2633 | ucontrol->value.integer.value[0] = | 2805 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2634 | (snd_soc_read(widget->codec, reg) >> shift) & mask; | 2806 | if (dapm_kcontrol_is_powered(kcontrol)) |
2807 | val = (snd_soc_read(codec, reg) >> shift) & mask; | ||
2808 | else | ||
2809 | val = dapm_kcontrol_get_value(kcontrol); | ||
2810 | mutex_unlock(&card->dapm_mutex); | ||
2811 | |||
2635 | if (invert) | 2812 | if (invert) |
2636 | ucontrol->value.integer.value[0] = | 2813 | ucontrol->value.integer.value[0] = max - val; |
2637 | max - ucontrol->value.integer.value[0]; | 2814 | else |
2815 | ucontrol->value.integer.value[0] = val; | ||
2638 | 2816 | ||
2639 | return 0; | 2817 | return 0; |
2640 | } | 2818 | } |
@@ -2652,9 +2830,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
2652 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 2830 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
2653 | struct snd_ctl_elem_value *ucontrol) | 2831 | struct snd_ctl_elem_value *ucontrol) |
2654 | { | 2832 | { |
2655 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2833 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2656 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2657 | struct snd_soc_codec *codec = widget->codec; | ||
2658 | struct snd_soc_card *card = codec->card; | 2834 | struct snd_soc_card *card = codec->card; |
2659 | struct soc_mixer_control *mc = | 2835 | struct soc_mixer_control *mc = |
2660 | (struct soc_mixer_control *)kcontrol->private_value; | 2836 | (struct soc_mixer_control *)kcontrol->private_value; |
@@ -2666,10 +2842,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2666 | unsigned int val; | 2842 | unsigned int val; |
2667 | int connect, change; | 2843 | int connect, change; |
2668 | struct snd_soc_dapm_update update; | 2844 | struct snd_soc_dapm_update update; |
2669 | int wi; | ||
2670 | 2845 | ||
2671 | if (snd_soc_volsw_is_stereo(mc)) | 2846 | if (snd_soc_volsw_is_stereo(mc)) |
2672 | dev_warn(widget->dapm->dev, | 2847 | dev_warn(codec->dapm.dev, |
2673 | "ASoC: Control '%s' is stereo, which is not supported\n", | 2848 | "ASoC: Control '%s' is stereo, which is not supported\n", |
2674 | kcontrol->id.name); | 2849 | kcontrol->id.name); |
2675 | 2850 | ||
@@ -2678,29 +2853,26 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2678 | 2853 | ||
2679 | if (invert) | 2854 | if (invert) |
2680 | val = max - val; | 2855 | val = max - val; |
2681 | mask = mask << shift; | ||
2682 | val = val << shift; | ||
2683 | 2856 | ||
2684 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2857 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2685 | 2858 | ||
2686 | change = snd_soc_test_bits(widget->codec, reg, mask, val); | 2859 | dapm_kcontrol_set_value(kcontrol, val); |
2687 | if (change) { | ||
2688 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
2689 | widget = wlist->widgets[wi]; | ||
2690 | 2860 | ||
2691 | widget->value = val; | 2861 | mask = mask << shift; |
2862 | val = val << shift; | ||
2692 | 2863 | ||
2693 | update.kcontrol = kcontrol; | 2864 | change = snd_soc_test_bits(codec, reg, mask, val); |
2694 | update.widget = widget; | 2865 | if (change) { |
2695 | update.reg = reg; | 2866 | update.kcontrol = kcontrol; |
2696 | update.mask = mask; | 2867 | update.reg = reg; |
2697 | update.val = val; | 2868 | update.mask = mask; |
2698 | widget->dapm->update = &update; | 2869 | update.val = val; |
2699 | 2870 | ||
2700 | soc_dapm_mixer_update_power(widget, kcontrol, connect); | 2871 | card->update = &update; |
2701 | 2872 | ||
2702 | widget->dapm->update = NULL; | 2873 | soc_dapm_mixer_update_power(card, kcontrol, connect); |
2703 | } | 2874 | |
2875 | card->update = NULL; | ||
2704 | } | 2876 | } |
2705 | 2877 | ||
2706 | mutex_unlock(&card->dapm_mutex); | 2878 | mutex_unlock(&card->dapm_mutex); |
@@ -2720,12 +2892,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
2720 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | 2892 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, |
2721 | struct snd_ctl_elem_value *ucontrol) | 2893 | struct snd_ctl_elem_value *ucontrol) |
2722 | { | 2894 | { |
2723 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2895 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2724 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2725 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2896 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2726 | unsigned int val; | 2897 | unsigned int val; |
2727 | 2898 | ||
2728 | val = snd_soc_read(widget->codec, e->reg); | 2899 | val = snd_soc_read(codec, e->reg); |
2729 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; | 2900 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; |
2730 | if (e->shift_l != e->shift_r) | 2901 | if (e->shift_l != e->shift_r) |
2731 | ucontrol->value.enumerated.item[1] = | 2902 | ucontrol->value.enumerated.item[1] = |
@@ -2747,15 +2918,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
2747 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 2918 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
2748 | struct snd_ctl_elem_value *ucontrol) | 2919 | struct snd_ctl_elem_value *ucontrol) |
2749 | { | 2920 | { |
2750 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2921 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2751 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2752 | struct snd_soc_codec *codec = widget->codec; | ||
2753 | struct snd_soc_card *card = codec->card; | 2922 | struct snd_soc_card *card = codec->card; |
2754 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2923 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2755 | unsigned int val, mux, change; | 2924 | unsigned int val, mux, change; |
2756 | unsigned int mask; | 2925 | unsigned int mask; |
2757 | struct snd_soc_dapm_update update; | 2926 | struct snd_soc_dapm_update update; |
2758 | int wi; | ||
2759 | 2927 | ||
2760 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2928 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2761 | return -EINVAL; | 2929 | return -EINVAL; |
@@ -2771,24 +2939,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2771 | 2939 | ||
2772 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2940 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2773 | 2941 | ||
2774 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2942 | change = snd_soc_test_bits(codec, e->reg, mask, val); |
2775 | if (change) { | 2943 | if (change) { |
2776 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 2944 | update.kcontrol = kcontrol; |
2777 | widget = wlist->widgets[wi]; | 2945 | update.reg = e->reg; |
2778 | 2946 | update.mask = mask; | |
2779 | widget->value = val; | 2947 | update.val = val; |
2948 | card->update = &update; | ||
2780 | 2949 | ||
2781 | update.kcontrol = kcontrol; | 2950 | soc_dapm_mux_update_power(card, kcontrol, mux, e); |
2782 | update.widget = widget; | ||
2783 | update.reg = e->reg; | ||
2784 | update.mask = mask; | ||
2785 | update.val = val; | ||
2786 | widget->dapm->update = &update; | ||
2787 | 2951 | ||
2788 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 2952 | card->update = NULL; |
2789 | |||
2790 | widget->dapm->update = NULL; | ||
2791 | } | ||
2792 | } | 2953 | } |
2793 | 2954 | ||
2794 | mutex_unlock(&card->dapm_mutex); | 2955 | mutex_unlock(&card->dapm_mutex); |
@@ -2806,11 +2967,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | |||
2806 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | 2967 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, |
2807 | struct snd_ctl_elem_value *ucontrol) | 2968 | struct snd_ctl_elem_value *ucontrol) |
2808 | { | 2969 | { |
2809 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2970 | ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol); |
2810 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2811 | |||
2812 | ucontrol->value.enumerated.item[0] = widget->value; | ||
2813 | |||
2814 | return 0; | 2971 | return 0; |
2815 | } | 2972 | } |
2816 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | 2973 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); |
@@ -2825,30 +2982,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | |||
2825 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | 2982 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, |
2826 | struct snd_ctl_elem_value *ucontrol) | 2983 | struct snd_ctl_elem_value *ucontrol) |
2827 | { | 2984 | { |
2828 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2985 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2829 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2830 | struct snd_soc_codec *codec = widget->codec; | ||
2831 | struct snd_soc_card *card = codec->card; | 2986 | struct snd_soc_card *card = codec->card; |
2987 | unsigned int value; | ||
2832 | struct soc_enum *e = | 2988 | struct soc_enum *e = |
2833 | (struct soc_enum *)kcontrol->private_value; | 2989 | (struct soc_enum *)kcontrol->private_value; |
2834 | int change; | 2990 | int change; |
2835 | int wi; | ||
2836 | 2991 | ||
2837 | if (ucontrol->value.enumerated.item[0] >= e->max) | 2992 | if (ucontrol->value.enumerated.item[0] >= e->max) |
2838 | return -EINVAL; | 2993 | return -EINVAL; |
2839 | 2994 | ||
2840 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2995 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2841 | 2996 | ||
2842 | change = widget->value != ucontrol->value.enumerated.item[0]; | 2997 | value = ucontrol->value.enumerated.item[0]; |
2843 | if (change) { | 2998 | change = dapm_kcontrol_set_value(kcontrol, value); |
2844 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 2999 | if (change) |
2845 | widget = wlist->widgets[wi]; | 3000 | soc_dapm_mux_update_power(card, kcontrol, value, e); |
2846 | |||
2847 | widget->value = ucontrol->value.enumerated.item[0]; | ||
2848 | |||
2849 | soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); | ||
2850 | } | ||
2851 | } | ||
2852 | 3001 | ||
2853 | mutex_unlock(&card->dapm_mutex); | 3002 | mutex_unlock(&card->dapm_mutex); |
2854 | return change; | 3003 | return change; |
@@ -2871,12 +3020,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | |||
2871 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | 3020 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, |
2872 | struct snd_ctl_elem_value *ucontrol) | 3021 | struct snd_ctl_elem_value *ucontrol) |
2873 | { | 3022 | { |
2874 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 3023 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2875 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2876 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 3024 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2877 | unsigned int reg_val, val, mux; | 3025 | unsigned int reg_val, val, mux; |
2878 | 3026 | ||
2879 | reg_val = snd_soc_read(widget->codec, e->reg); | 3027 | reg_val = snd_soc_read(codec, e->reg); |
2880 | val = (reg_val >> e->shift_l) & e->mask; | 3028 | val = (reg_val >> e->shift_l) & e->mask; |
2881 | for (mux = 0; mux < e->max; mux++) { | 3029 | for (mux = 0; mux < e->max; mux++) { |
2882 | if (val == e->values[mux]) | 3030 | if (val == e->values[mux]) |
@@ -2912,15 +3060,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | |||
2912 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 3060 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, |
2913 | struct snd_ctl_elem_value *ucontrol) | 3061 | struct snd_ctl_elem_value *ucontrol) |
2914 | { | 3062 | { |
2915 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 3063 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2916 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2917 | struct snd_soc_codec *codec = widget->codec; | ||
2918 | struct snd_soc_card *card = codec->card; | 3064 | struct snd_soc_card *card = codec->card; |
2919 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 3065 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2920 | unsigned int val, mux, change; | 3066 | unsigned int val, mux, change; |
2921 | unsigned int mask; | 3067 | unsigned int mask; |
2922 | struct snd_soc_dapm_update update; | 3068 | struct snd_soc_dapm_update update; |
2923 | int wi; | ||
2924 | 3069 | ||
2925 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 3070 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
2926 | return -EINVAL; | 3071 | return -EINVAL; |
@@ -2936,24 +3081,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2936 | 3081 | ||
2937 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 3082 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2938 | 3083 | ||
2939 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 3084 | change = snd_soc_test_bits(codec, e->reg, mask, val); |
2940 | if (change) { | 3085 | if (change) { |
2941 | for (wi = 0; wi < wlist->num_widgets; wi++) { | 3086 | update.kcontrol = kcontrol; |
2942 | widget = wlist->widgets[wi]; | 3087 | update.reg = e->reg; |
2943 | 3088 | update.mask = mask; | |
2944 | widget->value = val; | 3089 | update.val = val; |
3090 | card->update = &update; | ||
2945 | 3091 | ||
2946 | update.kcontrol = kcontrol; | 3092 | soc_dapm_mux_update_power(card, kcontrol, mux, e); |
2947 | update.widget = widget; | ||
2948 | update.reg = e->reg; | ||
2949 | update.mask = mask; | ||
2950 | update.val = val; | ||
2951 | widget->dapm->update = &update; | ||
2952 | 3093 | ||
2953 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 3094 | card->update = NULL; |
2954 | |||
2955 | widget->dapm->update = NULL; | ||
2956 | } | ||
2957 | } | 3095 | } |
2958 | 3096 | ||
2959 | mutex_unlock(&card->dapm_mutex); | 3097 | mutex_unlock(&card->dapm_mutex); |
@@ -3050,7 +3188,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3050 | return NULL; | 3188 | return NULL; |
3051 | } | 3189 | } |
3052 | 3190 | ||
3053 | if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { | 3191 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
3054 | ret = regulator_allow_bypass(w->regulator, true); | 3192 | ret = regulator_allow_bypass(w->regulator, true); |
3055 | if (ret != 0) | 3193 | if (ret != 0) |
3056 | dev_warn(w->dapm->dev, | 3194 | dev_warn(w->dapm->dev, |
@@ -3097,16 +3235,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3097 | case snd_soc_dapm_value_mux: | 3235 | case snd_soc_dapm_value_mux: |
3098 | w->power_check = dapm_generic_check_power; | 3236 | w->power_check = dapm_generic_check_power; |
3099 | break; | 3237 | break; |
3100 | case snd_soc_dapm_adc: | ||
3101 | case snd_soc_dapm_aif_out: | ||
3102 | case snd_soc_dapm_dai_out: | 3238 | case snd_soc_dapm_dai_out: |
3103 | w->power_check = dapm_adc_check_power; | 3239 | w->power_check = dapm_adc_check_power; |
3104 | break; | 3240 | break; |
3105 | case snd_soc_dapm_dac: | ||
3106 | case snd_soc_dapm_aif_in: | ||
3107 | case snd_soc_dapm_dai_in: | 3241 | case snd_soc_dapm_dai_in: |
3108 | w->power_check = dapm_dac_check_power; | 3242 | w->power_check = dapm_dac_check_power; |
3109 | break; | 3243 | break; |
3244 | case snd_soc_dapm_adc: | ||
3245 | case snd_soc_dapm_aif_out: | ||
3246 | case snd_soc_dapm_dac: | ||
3247 | case snd_soc_dapm_aif_in: | ||
3110 | case snd_soc_dapm_pga: | 3248 | case snd_soc_dapm_pga: |
3111 | case snd_soc_dapm_out_drv: | 3249 | case snd_soc_dapm_out_drv: |
3112 | case snd_soc_dapm_input: | 3250 | case snd_soc_dapm_input: |
@@ -3122,6 +3260,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3122 | case snd_soc_dapm_supply: | 3260 | case snd_soc_dapm_supply: |
3123 | case snd_soc_dapm_regulator_supply: | 3261 | case snd_soc_dapm_regulator_supply: |
3124 | case snd_soc_dapm_clock_supply: | 3262 | case snd_soc_dapm_clock_supply: |
3263 | case snd_soc_dapm_kcontrol: | ||
3125 | w->power_check = dapm_supply_check_power; | 3264 | w->power_check = dapm_supply_check_power; |
3126 | break; | 3265 | break; |
3127 | default: | 3266 | default: |
@@ -3386,9 +3525,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3386 | { | 3525 | { |
3387 | struct snd_soc_dapm_widget *dai_w, *w; | 3526 | struct snd_soc_dapm_widget *dai_w, *w; |
3388 | struct snd_soc_dai *dai; | 3527 | struct snd_soc_dai *dai; |
3389 | struct snd_soc_dapm_route r; | ||
3390 | |||
3391 | memset(&r, 0, sizeof(r)); | ||
3392 | 3528 | ||
3393 | /* For each DAI widget... */ | 3529 | /* For each DAI widget... */ |
3394 | list_for_each_entry(dai_w, &card->widgets, list) { | 3530 | list_for_each_entry(dai_w, &card->widgets, list) { |
@@ -3415,29 +3551,27 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
3415 | break; | 3551 | break; |
3416 | } | 3552 | } |
3417 | 3553 | ||
3418 | if (!w->sname) | 3554 | if (!w->sname || !strstr(w->sname, dai_w->name)) |
3419 | continue; | 3555 | continue; |
3420 | 3556 | ||
3421 | if (dai->driver->playback.stream_name && | 3557 | if (dai->driver->playback.stream_name && |
3422 | strstr(w->sname, | 3558 | strstr(w->sname, |
3423 | dai->driver->playback.stream_name)) { | 3559 | dai->driver->playback.stream_name)) { |
3424 | r.source = dai->playback_widget->name; | ||
3425 | r.sink = w->name; | ||
3426 | dev_dbg(dai->dev, "%s -> %s\n", | 3560 | dev_dbg(dai->dev, "%s -> %s\n", |
3427 | r.source, r.sink); | 3561 | dai->playback_widget->name, w->name); |
3428 | 3562 | ||
3429 | snd_soc_dapm_add_route(w->dapm, &r); | 3563 | snd_soc_dapm_add_path(w->dapm, |
3564 | dai->playback_widget, w, NULL, NULL); | ||
3430 | } | 3565 | } |
3431 | 3566 | ||
3432 | if (dai->driver->capture.stream_name && | 3567 | if (dai->driver->capture.stream_name && |
3433 | strstr(w->sname, | 3568 | strstr(w->sname, |
3434 | dai->driver->capture.stream_name)) { | 3569 | dai->driver->capture.stream_name)) { |
3435 | r.source = w->name; | ||
3436 | r.sink = dai->capture_widget->name; | ||
3437 | dev_dbg(dai->dev, "%s -> %s\n", | 3570 | dev_dbg(dai->dev, "%s -> %s\n", |
3438 | r.source, r.sink); | 3571 | w->name, dai->capture_widget->name); |
3439 | 3572 | ||
3440 | snd_soc_dapm_add_route(w->dapm, &r); | 3573 | snd_soc_dapm_add_path(w->dapm, w, |
3574 | dai->capture_widget, NULL, NULL); | ||
3441 | } | 3575 | } |
3442 | } | 3576 | } |
3443 | } | 3577 | } |
@@ -3499,7 +3633,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | |||
3499 | } | 3633 | } |
3500 | } | 3634 | } |
3501 | 3635 | ||
3502 | dapm_power_widgets(&rtd->card->dapm, event); | 3636 | dapm_power_widgets(rtd->card, event); |
3503 | } | 3637 | } |
3504 | 3638 | ||
3505 | /** | 3639 | /** |
@@ -3768,7 +3902,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
3768 | if (dapm->bias_level == SND_SOC_BIAS_ON) | 3902 | if (dapm->bias_level == SND_SOC_BIAS_ON) |
3769 | snd_soc_dapm_set_bias_level(dapm, | 3903 | snd_soc_dapm_set_bias_level(dapm, |
3770 | SND_SOC_BIAS_PREPARE); | 3904 | SND_SOC_BIAS_PREPARE); |
3771 | dapm_seq_run(dapm, &down_list, 0, false); | 3905 | dapm_seq_run(card, &down_list, 0, false); |
3772 | if (dapm->bias_level == SND_SOC_BIAS_PREPARE) | 3906 | if (dapm->bias_level == SND_SOC_BIAS_PREPARE) |
3773 | snd_soc_dapm_set_bias_level(dapm, | 3907 | snd_soc_dapm_set_bias_level(dapm, |
3774 | SND_SOC_BIAS_STANDBY); | 3908 | SND_SOC_BIAS_STANDBY); |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f4f68cb3cb00..fb70fbe26862 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -1833,18 +1833,10 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) | |||
1833 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and | 1833 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and |
1834 | * any DAI links. | 1834 | * any DAI links. |
1835 | */ | 1835 | */ |
1836 | int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) | 1836 | int soc_dpcm_runtime_update(struct snd_soc_card *card) |
1837 | { | 1837 | { |
1838 | struct snd_soc_card *card; | ||
1839 | int i, old, new, paths; | 1838 | int i, old, new, paths; |
1840 | 1839 | ||
1841 | if (widget->codec) | ||
1842 | card = widget->codec->card; | ||
1843 | else if (widget->platform) | ||
1844 | card = widget->platform->card; | ||
1845 | else | ||
1846 | return -EINVAL; | ||
1847 | |||
1848 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 1840 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
1849 | for (i = 0; i < card->num_rtd; i++) { | 1841 | for (i = 0; i < card->num_rtd; i++) { |
1850 | struct snd_soc_dapm_widget_list *list; | 1842 | struct snd_soc_dapm_widget_list *list; |