diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/soc/soc-dapm.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 1503 |
1 files changed, 963 insertions, 540 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 03cb7c05ebec..32ab7fc4579a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/moduleparam.h> | 33 | #include <linux/moduleparam.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/async.h> | ||
35 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
36 | #include <linux/pm.h> | 37 | #include <linux/pm.h> |
37 | #include <linux/bitops.h> | 38 | #include <linux/bitops.h> |
@@ -42,9 +43,11 @@ | |||
42 | #include <sound/core.h> | 43 | #include <sound/core.h> |
43 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
44 | #include <sound/pcm_params.h> | 45 | #include <sound/pcm_params.h> |
45 | #include <sound/soc-dapm.h> | 46 | #include <sound/soc.h> |
46 | #include <sound/initval.h> | 47 | #include <sound/initval.h> |
47 | 48 | ||
49 | #include <trace/events/asoc.h> | ||
50 | |||
48 | /* dapm power sequences - make this per codec in the future */ | 51 | /* dapm power sequences - make this per codec in the future */ |
49 | static int dapm_up_seq[] = { | 52 | static int dapm_up_seq[] = { |
50 | [snd_soc_dapm_pre] = 0, | 53 | [snd_soc_dapm_pre] = 0, |
@@ -54,12 +57,14 @@ static int dapm_up_seq[] = { | |||
54 | [snd_soc_dapm_aif_out] = 3, | 57 | [snd_soc_dapm_aif_out] = 3, |
55 | [snd_soc_dapm_mic] = 4, | 58 | [snd_soc_dapm_mic] = 4, |
56 | [snd_soc_dapm_mux] = 5, | 59 | [snd_soc_dapm_mux] = 5, |
60 | [snd_soc_dapm_virt_mux] = 5, | ||
57 | [snd_soc_dapm_value_mux] = 5, | 61 | [snd_soc_dapm_value_mux] = 5, |
58 | [snd_soc_dapm_dac] = 6, | 62 | [snd_soc_dapm_dac] = 6, |
59 | [snd_soc_dapm_mixer] = 7, | 63 | [snd_soc_dapm_mixer] = 7, |
60 | [snd_soc_dapm_mixer_named_ctl] = 7, | 64 | [snd_soc_dapm_mixer_named_ctl] = 7, |
61 | [snd_soc_dapm_pga] = 8, | 65 | [snd_soc_dapm_pga] = 8, |
62 | [snd_soc_dapm_adc] = 9, | 66 | [snd_soc_dapm_adc] = 9, |
67 | [snd_soc_dapm_out_drv] = 10, | ||
63 | [snd_soc_dapm_hp] = 10, | 68 | [snd_soc_dapm_hp] = 10, |
64 | [snd_soc_dapm_spk] = 10, | 69 | [snd_soc_dapm_spk] = 10, |
65 | [snd_soc_dapm_post] = 11, | 70 | [snd_soc_dapm_post] = 11, |
@@ -70,6 +75,7 @@ static int dapm_down_seq[] = { | |||
70 | [snd_soc_dapm_adc] = 1, | 75 | [snd_soc_dapm_adc] = 1, |
71 | [snd_soc_dapm_hp] = 2, | 76 | [snd_soc_dapm_hp] = 2, |
72 | [snd_soc_dapm_spk] = 2, | 77 | [snd_soc_dapm_spk] = 2, |
78 | [snd_soc_dapm_out_drv] = 2, | ||
73 | [snd_soc_dapm_pga] = 4, | 79 | [snd_soc_dapm_pga] = 4, |
74 | [snd_soc_dapm_mixer_named_ctl] = 5, | 80 | [snd_soc_dapm_mixer_named_ctl] = 5, |
75 | [snd_soc_dapm_mixer] = 5, | 81 | [snd_soc_dapm_mixer] = 5, |
@@ -77,6 +83,7 @@ static int dapm_down_seq[] = { | |||
77 | [snd_soc_dapm_mic] = 7, | 83 | [snd_soc_dapm_mic] = 7, |
78 | [snd_soc_dapm_micbias] = 8, | 84 | [snd_soc_dapm_micbias] = 8, |
79 | [snd_soc_dapm_mux] = 9, | 85 | [snd_soc_dapm_mux] = 9, |
86 | [snd_soc_dapm_virt_mux] = 9, | ||
80 | [snd_soc_dapm_value_mux] = 9, | 87 | [snd_soc_dapm_value_mux] = 9, |
81 | [snd_soc_dapm_aif_in] = 10, | 88 | [snd_soc_dapm_aif_in] = 10, |
82 | [snd_soc_dapm_aif_out] = 10, | 89 | [snd_soc_dapm_aif_out] = 10, |
@@ -90,17 +97,24 @@ static void pop_wait(u32 pop_time) | |||
90 | schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); | 97 | schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); |
91 | } | 98 | } |
92 | 99 | ||
93 | static void pop_dbg(u32 pop_time, const char *fmt, ...) | 100 | static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...) |
94 | { | 101 | { |
95 | va_list args; | 102 | va_list args; |
103 | char *buf; | ||
96 | 104 | ||
97 | va_start(args, fmt); | 105 | if (!pop_time) |
106 | return; | ||
98 | 107 | ||
99 | if (pop_time) { | 108 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
100 | vprintk(fmt, args); | 109 | if (buf == NULL) |
101 | } | 110 | return; |
102 | 111 | ||
112 | va_start(args, fmt); | ||
113 | vsnprintf(buf, PAGE_SIZE, fmt, args); | ||
114 | dev_info(dev, "%s", buf); | ||
103 | va_end(args); | 115 | va_end(args); |
116 | |||
117 | kfree(buf); | ||
104 | } | 118 | } |
105 | 119 | ||
106 | /* create a new dapm widget */ | 120 | /* create a new dapm widget */ |
@@ -112,47 +126,54 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | |||
112 | 126 | ||
113 | /** | 127 | /** |
114 | * snd_soc_dapm_set_bias_level - set the bias level for the system | 128 | * snd_soc_dapm_set_bias_level - set the bias level for the system |
115 | * @socdev: audio device | 129 | * @dapm: DAPM context |
116 | * @level: level to configure | 130 | * @level: level to configure |
117 | * | 131 | * |
118 | * Configure the bias (power) levels for the SoC audio device. | 132 | * Configure the bias (power) levels for the SoC audio device. |
119 | * | 133 | * |
120 | * Returns 0 for success else error. | 134 | * Returns 0 for success else error. |
121 | */ | 135 | */ |
122 | static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, | 136 | static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, |
123 | enum snd_soc_bias_level level) | 137 | enum snd_soc_bias_level level) |
124 | { | 138 | { |
125 | struct snd_soc_card *card = socdev->card; | 139 | struct snd_soc_card *card = dapm->card; |
126 | struct snd_soc_codec *codec = socdev->card->codec; | ||
127 | int ret = 0; | 140 | int ret = 0; |
128 | 141 | ||
129 | switch (level) { | 142 | switch (level) { |
130 | case SND_SOC_BIAS_ON: | 143 | case SND_SOC_BIAS_ON: |
131 | dev_dbg(socdev->dev, "Setting full bias\n"); | 144 | dev_dbg(dapm->dev, "Setting full bias\n"); |
132 | break; | 145 | break; |
133 | case SND_SOC_BIAS_PREPARE: | 146 | case SND_SOC_BIAS_PREPARE: |
134 | dev_dbg(socdev->dev, "Setting bias prepare\n"); | 147 | dev_dbg(dapm->dev, "Setting bias prepare\n"); |
135 | break; | 148 | break; |
136 | case SND_SOC_BIAS_STANDBY: | 149 | case SND_SOC_BIAS_STANDBY: |
137 | dev_dbg(socdev->dev, "Setting standby bias\n"); | 150 | dev_dbg(dapm->dev, "Setting standby bias\n"); |
138 | break; | 151 | break; |
139 | case SND_SOC_BIAS_OFF: | 152 | case SND_SOC_BIAS_OFF: |
140 | dev_dbg(socdev->dev, "Setting bias off\n"); | 153 | dev_dbg(dapm->dev, "Setting bias off\n"); |
141 | break; | 154 | break; |
142 | default: | 155 | default: |
143 | dev_err(socdev->dev, "Setting invalid bias %d\n", level); | 156 | dev_err(dapm->dev, "Setting invalid bias %d\n", level); |
144 | return -EINVAL; | 157 | return -EINVAL; |
145 | } | 158 | } |
146 | 159 | ||
147 | if (card->set_bias_level) | 160 | trace_snd_soc_bias_level_start(card, level); |
161 | |||
162 | if (card && card->set_bias_level) | ||
148 | ret = card->set_bias_level(card, level); | 163 | ret = card->set_bias_level(card, level); |
149 | if (ret == 0) { | 164 | if (ret == 0) { |
150 | if (codec->set_bias_level) | 165 | if (dapm->codec && dapm->codec->driver->set_bias_level) |
151 | ret = codec->set_bias_level(codec, level); | 166 | ret = dapm->codec->driver->set_bias_level(dapm->codec, level); |
152 | else | 167 | else |
153 | codec->bias_level = level; | 168 | dapm->bias_level = level; |
169 | } | ||
170 | if (ret == 0) { | ||
171 | if (card && card->set_bias_level_post) | ||
172 | ret = card->set_bias_level_post(card, level); | ||
154 | } | 173 | } |
155 | 174 | ||
175 | trace_snd_soc_bias_level_done(card, level); | ||
176 | |||
156 | return ret; | 177 | return ret; |
157 | } | 178 | } |
158 | 179 | ||
@@ -166,7 +187,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
166 | case snd_soc_dapm_mixer_named_ctl: { | 187 | case snd_soc_dapm_mixer_named_ctl: { |
167 | int val; | 188 | int val; |
168 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | 189 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
169 | w->kcontrols[i].private_value; | 190 | w->kcontrol_news[i].private_value; |
170 | unsigned int reg = mc->reg; | 191 | unsigned int reg = mc->reg; |
171 | unsigned int shift = mc->shift; | 192 | unsigned int shift = mc->shift; |
172 | int max = mc->max; | 193 | int max = mc->max; |
@@ -183,7 +204,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
183 | } | 204 | } |
184 | break; | 205 | break; |
185 | case snd_soc_dapm_mux: { | 206 | case snd_soc_dapm_mux: { |
186 | struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; | 207 | struct soc_enum *e = (struct soc_enum *) |
208 | w->kcontrol_news[i].private_value; | ||
187 | int val, item, bitmask; | 209 | int val, item, bitmask; |
188 | 210 | ||
189 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 211 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
@@ -198,9 +220,24 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
198 | } | 220 | } |
199 | } | 221 | } |
200 | break; | 222 | break; |
223 | case snd_soc_dapm_virt_mux: { | ||
224 | struct soc_enum *e = (struct soc_enum *) | ||
225 | w->kcontrol_news[i].private_value; | ||
226 | |||
227 | p->connect = 0; | ||
228 | /* since a virtual mux has no backing registers to | ||
229 | * decide which path to connect, it will try to match | ||
230 | * with the first enumeration. This is to ensure | ||
231 | * that the default mux choice (the first) will be | ||
232 | * correctly powered up during initialization. | ||
233 | */ | ||
234 | if (!strcmp(p->name, e->texts[0])) | ||
235 | p->connect = 1; | ||
236 | } | ||
237 | break; | ||
201 | case snd_soc_dapm_value_mux: { | 238 | case snd_soc_dapm_value_mux: { |
202 | struct soc_enum *e = (struct soc_enum *) | 239 | struct soc_enum *e = (struct soc_enum *) |
203 | w->kcontrols[i].private_value; | 240 | w->kcontrol_news[i].private_value; |
204 | int val, item; | 241 | int val, item; |
205 | 242 | ||
206 | val = snd_soc_read(w->codec, e->reg); | 243 | val = snd_soc_read(w->codec, e->reg); |
@@ -219,6 +256,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
219 | break; | 256 | break; |
220 | /* does not effect routing - always connected */ | 257 | /* does not effect routing - always connected */ |
221 | case snd_soc_dapm_pga: | 258 | case snd_soc_dapm_pga: |
259 | case snd_soc_dapm_out_drv: | ||
222 | case snd_soc_dapm_output: | 260 | case snd_soc_dapm_output: |
223 | case snd_soc_dapm_adc: | 261 | case snd_soc_dapm_adc: |
224 | case snd_soc_dapm_input: | 262 | case snd_soc_dapm_input: |
@@ -243,7 +281,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
243 | } | 281 | } |
244 | 282 | ||
245 | /* connect mux widget to its interconnecting audio paths */ | 283 | /* connect mux widget to its interconnecting audio paths */ |
246 | static int dapm_connect_mux(struct snd_soc_codec *codec, | 284 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
247 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 285 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
248 | struct snd_soc_dapm_path *path, const char *control_name, | 286 | struct snd_soc_dapm_path *path, const char *control_name, |
249 | const struct snd_kcontrol_new *kcontrol) | 287 | const struct snd_kcontrol_new *kcontrol) |
@@ -253,7 +291,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, | |||
253 | 291 | ||
254 | for (i = 0; i < e->max; i++) { | 292 | for (i = 0; i < e->max; i++) { |
255 | if (!(strcmp(control_name, e->texts[i]))) { | 293 | if (!(strcmp(control_name, e->texts[i]))) { |
256 | list_add(&path->list, &codec->dapm_paths); | 294 | list_add(&path->list, &dapm->card->paths); |
257 | list_add(&path->list_sink, &dest->sources); | 295 | list_add(&path->list_sink, &dest->sources); |
258 | list_add(&path->list_source, &src->sinks); | 296 | list_add(&path->list_source, &src->sinks); |
259 | path->name = (char*)e->texts[i]; | 297 | path->name = (char*)e->texts[i]; |
@@ -266,7 +304,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, | |||
266 | } | 304 | } |
267 | 305 | ||
268 | /* connect mixer widget to its interconnecting audio paths */ | 306 | /* connect mixer widget to its interconnecting audio paths */ |
269 | static int dapm_connect_mixer(struct snd_soc_codec *codec, | 307 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, |
270 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 308 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
271 | struct snd_soc_dapm_path *path, const char *control_name) | 309 | struct snd_soc_dapm_path *path, const char *control_name) |
272 | { | 310 | { |
@@ -274,11 +312,11 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec, | |||
274 | 312 | ||
275 | /* search for mixer kcontrol */ | 313 | /* search for mixer kcontrol */ |
276 | for (i = 0; i < dest->num_kcontrols; i++) { | 314 | for (i = 0; i < dest->num_kcontrols; i++) { |
277 | if (!strcmp(control_name, dest->kcontrols[i].name)) { | 315 | if (!strcmp(control_name, dest->kcontrol_news[i].name)) { |
278 | list_add(&path->list, &codec->dapm_paths); | 316 | list_add(&path->list, &dapm->card->paths); |
279 | list_add(&path->list_sink, &dest->sources); | 317 | list_add(&path->list_sink, &dest->sources); |
280 | list_add(&path->list_source, &src->sinks); | 318 | list_add(&path->list_source, &src->sinks); |
281 | path->name = dest->kcontrols[i].name; | 319 | path->name = dest->kcontrol_news[i].name; |
282 | dapm_set_path_status(dest, path, i); | 320 | dapm_set_path_status(dest, path, i); |
283 | return 0; | 321 | return 0; |
284 | } | 322 | } |
@@ -286,49 +324,52 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec, | |||
286 | return -ENODEV; | 324 | return -ENODEV; |
287 | } | 325 | } |
288 | 326 | ||
289 | /* update dapm codec register bits */ | 327 | static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, |
290 | static int dapm_update_bits(struct snd_soc_dapm_widget *widget) | 328 | struct snd_soc_dapm_widget *kcontrolw, |
329 | const struct snd_kcontrol_new *kcontrol_new, | ||
330 | struct snd_kcontrol **kcontrol) | ||
291 | { | 331 | { |
292 | int change, power; | 332 | struct snd_soc_dapm_widget *w; |
293 | unsigned int old, new; | 333 | int i; |
294 | struct snd_soc_codec *codec = widget->codec; | ||
295 | |||
296 | /* check for valid widgets */ | ||
297 | if (widget->reg < 0 || widget->id == snd_soc_dapm_input || | ||
298 | widget->id == snd_soc_dapm_output || | ||
299 | widget->id == snd_soc_dapm_hp || | ||
300 | widget->id == snd_soc_dapm_mic || | ||
301 | widget->id == snd_soc_dapm_line || | ||
302 | widget->id == snd_soc_dapm_spk) | ||
303 | return 0; | ||
304 | 334 | ||
305 | power = widget->power; | 335 | *kcontrol = NULL; |
306 | if (widget->invert) | ||
307 | power = (power ? 0:1); | ||
308 | 336 | ||
309 | old = snd_soc_read(codec, widget->reg); | 337 | list_for_each_entry(w, &dapm->card->widgets, list) { |
310 | new = (old & ~(0x1 << widget->shift)) | (power << widget->shift); | 338 | if (w == kcontrolw || w->dapm != kcontrolw->dapm) |
339 | continue; | ||
340 | for (i = 0; i < w->num_kcontrols; i++) { | ||
341 | if (&w->kcontrol_news[i] == kcontrol_new) { | ||
342 | if (w->kcontrols) | ||
343 | *kcontrol = w->kcontrols[i]; | ||
344 | return 1; | ||
345 | } | ||
346 | } | ||
347 | } | ||
311 | 348 | ||
312 | change = old != new; | 349 | return 0; |
313 | if (change) { | ||
314 | pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n", | ||
315 | widget->name, widget->power ? "on" : "off", | ||
316 | codec->pop_time); | ||
317 | pop_wait(codec->pop_time); | ||
318 | snd_soc_write(codec, widget->reg, new); | ||
319 | } | ||
320 | pr_debug("reg %x old %x new %x change %d\n", widget->reg, | ||
321 | old, new, change); | ||
322 | return change; | ||
323 | } | 350 | } |
324 | 351 | ||
325 | /* create new dapm mixer control */ | 352 | /* create new dapm mixer control */ |
326 | static int dapm_new_mixer(struct snd_soc_codec *codec, | 353 | static int dapm_new_mixer(struct snd_soc_dapm_widget *w) |
327 | struct snd_soc_dapm_widget *w) | ||
328 | { | 354 | { |
355 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
329 | int i, ret = 0; | 356 | int i, ret = 0; |
330 | size_t name_len; | 357 | size_t name_len, prefix_len; |
331 | struct snd_soc_dapm_path *path; | 358 | struct snd_soc_dapm_path *path; |
359 | struct snd_card *card = dapm->card->snd_card; | ||
360 | const char *prefix; | ||
361 | struct snd_soc_dapm_widget_list *wlist; | ||
362 | size_t wlistsize; | ||
363 | |||
364 | if (dapm->codec) | ||
365 | prefix = dapm->codec->name_prefix; | ||
366 | else | ||
367 | prefix = NULL; | ||
368 | |||
369 | if (prefix) | ||
370 | prefix_len = strlen(prefix) + 1; | ||
371 | else | ||
372 | prefix_len = 0; | ||
332 | 373 | ||
333 | /* add kcontrol */ | 374 | /* add kcontrol */ |
334 | for (i = 0; i < w->num_kcontrols; i++) { | 375 | for (i = 0; i < w->num_kcontrols; i++) { |
@@ -337,97 +378,178 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, | |||
337 | list_for_each_entry(path, &w->sources, list_sink) { | 378 | list_for_each_entry(path, &w->sources, list_sink) { |
338 | 379 | ||
339 | /* mixer/mux paths name must match control name */ | 380 | /* mixer/mux paths name must match control name */ |
340 | if (path->name != (char*)w->kcontrols[i].name) | 381 | if (path->name != (char *)w->kcontrol_news[i].name) |
341 | continue; | 382 | continue; |
342 | 383 | ||
384 | wlistsize = sizeof(struct snd_soc_dapm_widget_list) + | ||
385 | sizeof(struct snd_soc_dapm_widget *), | ||
386 | wlist = kzalloc(wlistsize, GFP_KERNEL); | ||
387 | if (wlist == NULL) { | ||
388 | dev_err(dapm->dev, | ||
389 | "asoc: can't allocate widget list for %s\n", | ||
390 | w->name); | ||
391 | return -ENOMEM; | ||
392 | } | ||
393 | wlist->num_widgets = 1; | ||
394 | wlist->widgets[0] = w; | ||
395 | |||
343 | /* add dapm control with long name. | 396 | /* add dapm control with long name. |
344 | * for dapm_mixer this is the concatenation of the | 397 | * for dapm_mixer this is the concatenation of the |
345 | * mixer and kcontrol name. | 398 | * mixer and kcontrol name. |
346 | * for dapm_mixer_named_ctl this is simply the | 399 | * for dapm_mixer_named_ctl this is simply the |
347 | * kcontrol name. | 400 | * kcontrol name. |
348 | */ | 401 | */ |
349 | name_len = strlen(w->kcontrols[i].name) + 1; | 402 | name_len = strlen(w->kcontrol_news[i].name) + 1; |
350 | if (w->id != snd_soc_dapm_mixer_named_ctl) | 403 | if (w->id != snd_soc_dapm_mixer_named_ctl) |
351 | name_len += 1 + strlen(w->name); | 404 | name_len += 1 + strlen(w->name); |
352 | 405 | ||
353 | path->long_name = kmalloc(name_len, GFP_KERNEL); | 406 | path->long_name = kmalloc(name_len, GFP_KERNEL); |
354 | 407 | ||
355 | if (path->long_name == NULL) | 408 | if (path->long_name == NULL) { |
409 | kfree(wlist); | ||
356 | return -ENOMEM; | 410 | return -ENOMEM; |
411 | } | ||
357 | 412 | ||
358 | switch (w->id) { | 413 | switch (w->id) { |
359 | default: | 414 | default: |
415 | /* The control will get a prefix from | ||
416 | * the control creation process but | ||
417 | * we're also using the same prefix | ||
418 | * for widgets so cut the prefix off | ||
419 | * the front of the widget name. | ||
420 | */ | ||
360 | snprintf(path->long_name, name_len, "%s %s", | 421 | snprintf(path->long_name, name_len, "%s %s", |
361 | w->name, w->kcontrols[i].name); | 422 | w->name + prefix_len, |
423 | w->kcontrol_news[i].name); | ||
362 | break; | 424 | break; |
363 | case snd_soc_dapm_mixer_named_ctl: | 425 | case snd_soc_dapm_mixer_named_ctl: |
364 | snprintf(path->long_name, name_len, "%s", | 426 | snprintf(path->long_name, name_len, "%s", |
365 | w->kcontrols[i].name); | 427 | w->kcontrol_news[i].name); |
366 | break; | 428 | break; |
367 | } | 429 | } |
368 | 430 | ||
369 | path->long_name[name_len - 1] = '\0'; | 431 | path->long_name[name_len - 1] = '\0'; |
370 | 432 | ||
371 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, | 433 | path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], |
372 | path->long_name); | 434 | wlist, path->long_name, |
373 | ret = snd_ctl_add(codec->card, path->kcontrol); | 435 | prefix); |
436 | ret = snd_ctl_add(card, path->kcontrol); | ||
374 | if (ret < 0) { | 437 | if (ret < 0) { |
375 | printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n", | 438 | dev_err(dapm->dev, |
376 | path->long_name, | 439 | "asoc: failed to add dapm kcontrol %s: %d\n", |
377 | ret); | 440 | path->long_name, ret); |
441 | kfree(wlist); | ||
378 | kfree(path->long_name); | 442 | kfree(path->long_name); |
379 | path->long_name = NULL; | 443 | path->long_name = NULL; |
380 | return ret; | 444 | return ret; |
381 | } | 445 | } |
446 | w->kcontrols[i] = path->kcontrol; | ||
382 | } | 447 | } |
383 | } | 448 | } |
384 | return ret; | 449 | return ret; |
385 | } | 450 | } |
386 | 451 | ||
387 | /* create new dapm mux control */ | 452 | /* create new dapm mux control */ |
388 | static int dapm_new_mux(struct snd_soc_codec *codec, | 453 | static int dapm_new_mux(struct snd_soc_dapm_widget *w) |
389 | struct snd_soc_dapm_widget *w) | ||
390 | { | 454 | { |
455 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
391 | struct snd_soc_dapm_path *path = NULL; | 456 | struct snd_soc_dapm_path *path = NULL; |
392 | struct snd_kcontrol *kcontrol; | 457 | struct snd_kcontrol *kcontrol; |
393 | int ret = 0; | 458 | struct snd_card *card = dapm->card->snd_card; |
394 | 459 | const char *prefix; | |
395 | if (!w->num_kcontrols) { | 460 | size_t prefix_len; |
396 | printk(KERN_ERR "asoc: mux %s has no controls\n", w->name); | 461 | int ret; |
462 | struct snd_soc_dapm_widget_list *wlist; | ||
463 | int shared, wlistentries; | ||
464 | size_t wlistsize; | ||
465 | char *name; | ||
466 | |||
467 | if (w->num_kcontrols != 1) { | ||
468 | dev_err(dapm->dev, | ||
469 | "asoc: mux %s has incorrect number of controls\n", | ||
470 | w->name); | ||
397 | return -EINVAL; | 471 | return -EINVAL; |
398 | } | 472 | } |
399 | 473 | ||
400 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); | 474 | shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0], |
401 | ret = snd_ctl_add(codec->card, kcontrol); | 475 | &kcontrol); |
402 | if (ret < 0) | 476 | if (kcontrol) { |
403 | goto err; | 477 | wlist = kcontrol->private_data; |
478 | wlistentries = wlist->num_widgets + 1; | ||
479 | } else { | ||
480 | wlist = NULL; | ||
481 | wlistentries = 1; | ||
482 | } | ||
483 | wlistsize = sizeof(struct snd_soc_dapm_widget_list) + | ||
484 | wlistentries * sizeof(struct snd_soc_dapm_widget *), | ||
485 | wlist = krealloc(wlist, wlistsize, GFP_KERNEL); | ||
486 | if (wlist == NULL) { | ||
487 | dev_err(dapm->dev, | ||
488 | "asoc: can't allocate widget list for %s\n", w->name); | ||
489 | return -ENOMEM; | ||
490 | } | ||
491 | wlist->num_widgets = wlistentries; | ||
492 | wlist->widgets[wlistentries - 1] = w; | ||
493 | |||
494 | if (!kcontrol) { | ||
495 | if (dapm->codec) | ||
496 | prefix = dapm->codec->name_prefix; | ||
497 | else | ||
498 | prefix = NULL; | ||
499 | |||
500 | if (shared) { | ||
501 | name = w->kcontrol_news[0].name; | ||
502 | prefix_len = 0; | ||
503 | } else { | ||
504 | name = w->name; | ||
505 | if (prefix) | ||
506 | prefix_len = strlen(prefix) + 1; | ||
507 | else | ||
508 | prefix_len = 0; | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * The control will get a prefix from the control creation | ||
513 | * process but we're also using the same prefix for widgets so | ||
514 | * cut the prefix off the front of the widget name. | ||
515 | */ | ||
516 | kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist, | ||
517 | name + prefix_len, prefix); | ||
518 | ret = snd_ctl_add(card, kcontrol); | ||
519 | if (ret < 0) { | ||
520 | dev_err(dapm->dev, | ||
521 | "asoc: failed to add kcontrol %s\n", w->name); | ||
522 | kfree(wlist); | ||
523 | return ret; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | kcontrol->private_data = wlist; | ||
528 | |||
529 | w->kcontrols[0] = kcontrol; | ||
404 | 530 | ||
405 | list_for_each_entry(path, &w->sources, list_sink) | 531 | list_for_each_entry(path, &w->sources, list_sink) |
406 | path->kcontrol = kcontrol; | 532 | path->kcontrol = kcontrol; |
407 | 533 | ||
408 | return ret; | 534 | return 0; |
409 | |||
410 | err: | ||
411 | printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); | ||
412 | return ret; | ||
413 | } | 535 | } |
414 | 536 | ||
415 | /* create new dapm volume control */ | 537 | /* create new dapm volume control */ |
416 | static int dapm_new_pga(struct snd_soc_codec *codec, | 538 | static int dapm_new_pga(struct snd_soc_dapm_widget *w) |
417 | struct snd_soc_dapm_widget *w) | ||
418 | { | 539 | { |
419 | if (w->num_kcontrols) | 540 | if (w->num_kcontrols) |
420 | pr_err("asoc: PGA controls not supported: '%s'\n", w->name); | 541 | dev_err(w->dapm->dev, |
542 | "asoc: PGA controls not supported: '%s'\n", w->name); | ||
421 | 543 | ||
422 | return 0; | 544 | return 0; |
423 | } | 545 | } |
424 | 546 | ||
425 | /* reset 'walked' bit for each dapm path */ | 547 | /* reset 'walked' bit for each dapm path */ |
426 | static inline void dapm_clear_walk(struct snd_soc_codec *codec) | 548 | static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) |
427 | { | 549 | { |
428 | struct snd_soc_dapm_path *p; | 550 | struct snd_soc_dapm_path *p; |
429 | 551 | ||
430 | list_for_each_entry(p, &codec->dapm_paths, list) | 552 | list_for_each_entry(p, &dapm->card->paths, list) |
431 | p->walked = 0; | 553 | p->walked = 0; |
432 | } | 554 | } |
433 | 555 | ||
@@ -437,13 +559,14 @@ static inline void dapm_clear_walk(struct snd_soc_codec *codec) | |||
437 | */ | 559 | */ |
438 | static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) | 560 | static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) |
439 | { | 561 | { |
440 | struct snd_soc_codec *codec = widget->codec; | 562 | int level = snd_power_get_state(widget->dapm->card->snd_card); |
441 | 563 | ||
442 | switch (snd_power_get_state(codec->card)) { | 564 | switch (level) { |
443 | case SNDRV_CTL_POWER_D3hot: | 565 | case SNDRV_CTL_POWER_D3hot: |
444 | case SNDRV_CTL_POWER_D3cold: | 566 | case SNDRV_CTL_POWER_D3cold: |
445 | if (widget->ignore_suspend) | 567 | if (widget->ignore_suspend) |
446 | pr_debug("%s ignoring suspend\n", widget->name); | 568 | dev_dbg(widget->dapm->dev, "%s ignoring suspend\n", |
569 | widget->name); | ||
447 | return widget->ignore_suspend; | 570 | return widget->ignore_suspend; |
448 | default: | 571 | default: |
449 | return 1; | 572 | return 1; |
@@ -565,57 +688,6 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, | |||
565 | } | 688 | } |
566 | EXPORT_SYMBOL_GPL(dapm_reg_event); | 689 | EXPORT_SYMBOL_GPL(dapm_reg_event); |
567 | 690 | ||
568 | /* Standard power change method, used to apply power changes to most | ||
569 | * widgets. | ||
570 | */ | ||
571 | static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w) | ||
572 | { | ||
573 | int ret; | ||
574 | |||
575 | /* call any power change event handlers */ | ||
576 | if (w->event) | ||
577 | pr_debug("power %s event for %s flags %x\n", | ||
578 | w->power ? "on" : "off", | ||
579 | w->name, w->event_flags); | ||
580 | |||
581 | /* power up pre event */ | ||
582 | if (w->power && w->event && | ||
583 | (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { | ||
584 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); | ||
585 | if (ret < 0) | ||
586 | return ret; | ||
587 | } | ||
588 | |||
589 | /* power down pre event */ | ||
590 | if (!w->power && w->event && | ||
591 | (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { | ||
592 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); | ||
593 | if (ret < 0) | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | dapm_update_bits(w); | ||
598 | |||
599 | /* power up post event */ | ||
600 | if (w->power && w->event && | ||
601 | (w->event_flags & SND_SOC_DAPM_POST_PMU)) { | ||
602 | ret = w->event(w, | ||
603 | NULL, SND_SOC_DAPM_POST_PMU); | ||
604 | if (ret < 0) | ||
605 | return ret; | ||
606 | } | ||
607 | |||
608 | /* power down post event */ | ||
609 | if (!w->power && w->event && | ||
610 | (w->event_flags & SND_SOC_DAPM_POST_PMD)) { | ||
611 | ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); | ||
612 | if (ret < 0) | ||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | /* Generic check to see if a widget should be powered. | 691 | /* Generic check to see if a widget should be powered. |
620 | */ | 692 | */ |
621 | static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | 693 | static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) |
@@ -623,9 +695,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | |||
623 | int in, out; | 695 | int in, out; |
624 | 696 | ||
625 | in = is_connected_input_ep(w); | 697 | in = is_connected_input_ep(w); |
626 | dapm_clear_walk(w->codec); | 698 | dapm_clear_walk(w->dapm); |
627 | out = is_connected_output_ep(w); | 699 | out = is_connected_output_ep(w); |
628 | dapm_clear_walk(w->codec); | 700 | dapm_clear_walk(w->dapm); |
629 | return out != 0 && in != 0; | 701 | return out != 0 && in != 0; |
630 | } | 702 | } |
631 | 703 | ||
@@ -636,7 +708,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) | |||
636 | 708 | ||
637 | if (w->active) { | 709 | if (w->active) { |
638 | in = is_connected_input_ep(w); | 710 | in = is_connected_input_ep(w); |
639 | dapm_clear_walk(w->codec); | 711 | dapm_clear_walk(w->dapm); |
640 | return in != 0; | 712 | return in != 0; |
641 | } else { | 713 | } else { |
642 | return dapm_generic_check_power(w); | 714 | return dapm_generic_check_power(w); |
@@ -650,7 +722,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) | |||
650 | 722 | ||
651 | if (w->active) { | 723 | if (w->active) { |
652 | out = is_connected_output_ep(w); | 724 | out = is_connected_output_ep(w); |
653 | dapm_clear_walk(w->codec); | 725 | dapm_clear_walk(w->dapm); |
654 | return out != 0; | 726 | return out != 0; |
655 | } else { | 727 | } else { |
656 | return dapm_generic_check_power(w); | 728 | return dapm_generic_check_power(w); |
@@ -669,28 +741,49 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
669 | !path->connected(path->source, path->sink)) | 741 | !path->connected(path->source, path->sink)) |
670 | continue; | 742 | continue; |
671 | 743 | ||
672 | if (path->sink && path->sink->power_check && | 744 | if (!path->sink) |
745 | continue; | ||
746 | |||
747 | if (path->sink->force) { | ||
748 | power = 1; | ||
749 | break; | ||
750 | } | ||
751 | |||
752 | if (path->sink->power_check && | ||
673 | path->sink->power_check(path->sink)) { | 753 | path->sink->power_check(path->sink)) { |
674 | power = 1; | 754 | power = 1; |
675 | break; | 755 | break; |
676 | } | 756 | } |
677 | } | 757 | } |
678 | 758 | ||
679 | dapm_clear_walk(w->codec); | 759 | dapm_clear_walk(w->dapm); |
680 | 760 | ||
681 | return power; | 761 | return power; |
682 | } | 762 | } |
683 | 763 | ||
684 | static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | 764 | static int dapm_seq_compare(struct snd_soc_dapm_widget *a, |
685 | struct snd_soc_dapm_widget *b, | 765 | struct snd_soc_dapm_widget *b, |
686 | int sort[]) | 766 | bool power_up) |
687 | { | 767 | { |
688 | if (a->codec != b->codec) | 768 | int *sort; |
689 | return (unsigned long)a - (unsigned long)b; | 769 | |
770 | if (power_up) | ||
771 | sort = dapm_up_seq; | ||
772 | else | ||
773 | sort = dapm_down_seq; | ||
774 | |||
690 | if (sort[a->id] != sort[b->id]) | 775 | if (sort[a->id] != sort[b->id]) |
691 | return sort[a->id] - sort[b->id]; | 776 | return sort[a->id] - sort[b->id]; |
777 | if (a->subseq != b->subseq) { | ||
778 | if (power_up) | ||
779 | return a->subseq - b->subseq; | ||
780 | else | ||
781 | return b->subseq - a->subseq; | ||
782 | } | ||
692 | if (a->reg != b->reg) | 783 | if (a->reg != b->reg) |
693 | return a->reg - b->reg; | 784 | return a->reg - b->reg; |
785 | if (a->dapm != b->dapm) | ||
786 | return (unsigned long)a->dapm - (unsigned long)b->dapm; | ||
694 | 787 | ||
695 | return 0; | 788 | return 0; |
696 | } | 789 | } |
@@ -698,12 +791,12 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | |||
698 | /* Insert a widget in order into a DAPM power sequence. */ | 791 | /* Insert a widget in order into a DAPM power sequence. */ |
699 | static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, | 792 | static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, |
700 | struct list_head *list, | 793 | struct list_head *list, |
701 | int sort[]) | 794 | bool power_up) |
702 | { | 795 | { |
703 | struct snd_soc_dapm_widget *w; | 796 | struct snd_soc_dapm_widget *w; |
704 | 797 | ||
705 | list_for_each_entry(w, list, power_list) | 798 | list_for_each_entry(w, list, power_list) |
706 | if (dapm_seq_compare(new_widget, w, sort) < 0) { | 799 | if (dapm_seq_compare(new_widget, w, power_up) < 0) { |
707 | list_add_tail(&new_widget->power_list, &w->power_list); | 800 | list_add_tail(&new_widget->power_list, &w->power_list); |
708 | return; | 801 | return; |
709 | } | 802 | } |
@@ -711,12 +804,57 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, | |||
711 | list_add_tail(&new_widget->power_list, list); | 804 | list_add_tail(&new_widget->power_list, list); |
712 | } | 805 | } |
713 | 806 | ||
807 | static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, | ||
808 | struct snd_soc_dapm_widget *w, int event) | ||
809 | { | ||
810 | struct snd_soc_card *card = dapm->card; | ||
811 | const char *ev_name; | ||
812 | int power, ret; | ||
813 | |||
814 | switch (event) { | ||
815 | case SND_SOC_DAPM_PRE_PMU: | ||
816 | ev_name = "PRE_PMU"; | ||
817 | power = 1; | ||
818 | break; | ||
819 | case SND_SOC_DAPM_POST_PMU: | ||
820 | ev_name = "POST_PMU"; | ||
821 | power = 1; | ||
822 | break; | ||
823 | case SND_SOC_DAPM_PRE_PMD: | ||
824 | ev_name = "PRE_PMD"; | ||
825 | power = 0; | ||
826 | break; | ||
827 | case SND_SOC_DAPM_POST_PMD: | ||
828 | ev_name = "POST_PMD"; | ||
829 | power = 0; | ||
830 | break; | ||
831 | default: | ||
832 | BUG(); | ||
833 | return; | ||
834 | } | ||
835 | |||
836 | if (w->power != power) | ||
837 | return; | ||
838 | |||
839 | if (w->event && (w->event_flags & event)) { | ||
840 | pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n", | ||
841 | w->name, ev_name); | ||
842 | trace_snd_soc_dapm_widget_event_start(w, event); | ||
843 | ret = w->event(w, NULL, event); | ||
844 | trace_snd_soc_dapm_widget_event_done(w, event); | ||
845 | if (ret < 0) | ||
846 | pr_err("%s: %s event failed: %d\n", | ||
847 | ev_name, w->name, ret); | ||
848 | } | ||
849 | } | ||
850 | |||
714 | /* Apply the coalesced changes from a DAPM sequence */ | 851 | /* Apply the coalesced changes from a DAPM sequence */ |
715 | static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, | 852 | static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, |
716 | struct list_head *pending) | 853 | struct list_head *pending) |
717 | { | 854 | { |
855 | struct snd_soc_card *card = dapm->card; | ||
718 | struct snd_soc_dapm_widget *w; | 856 | struct snd_soc_dapm_widget *w; |
719 | int reg, power, ret; | 857 | int reg, power; |
720 | unsigned int value = 0; | 858 | unsigned int value = 0; |
721 | unsigned int mask = 0; | 859 | unsigned int mask = 0; |
722 | unsigned int cur_mask; | 860 | unsigned int cur_mask; |
@@ -737,64 +875,26 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, | |||
737 | if (power) | 875 | if (power) |
738 | value |= cur_mask; | 876 | value |= cur_mask; |
739 | 877 | ||
740 | pop_dbg(codec->pop_time, | 878 | pop_dbg(dapm->dev, card->pop_time, |
741 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", | 879 | "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", |
742 | w->name, reg, value, mask); | 880 | w->name, reg, value, mask); |
743 | 881 | ||
744 | /* power up pre event */ | 882 | /* Check for events */ |
745 | if (w->power && w->event && | 883 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU); |
746 | (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { | 884 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD); |
747 | pop_dbg(codec->pop_time, "pop test : %s PRE_PMU\n", | ||
748 | w->name); | ||
749 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); | ||
750 | if (ret < 0) | ||
751 | pr_err("%s: pre event failed: %d\n", | ||
752 | w->name, ret); | ||
753 | } | ||
754 | |||
755 | /* power down pre event */ | ||
756 | if (!w->power && w->event && | ||
757 | (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { | ||
758 | pop_dbg(codec->pop_time, "pop test : %s PRE_PMD\n", | ||
759 | w->name); | ||
760 | ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); | ||
761 | if (ret < 0) | ||
762 | pr_err("%s: pre event failed: %d\n", | ||
763 | w->name, ret); | ||
764 | } | ||
765 | } | 885 | } |
766 | 886 | ||
767 | if (reg >= 0) { | 887 | if (reg >= 0) { |
768 | pop_dbg(codec->pop_time, | 888 | pop_dbg(dapm->dev, card->pop_time, |
769 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 889 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
770 | value, mask, reg, codec->pop_time); | 890 | value, mask, reg, card->pop_time); |
771 | pop_wait(codec->pop_time); | 891 | pop_wait(card->pop_time); |
772 | snd_soc_update_bits(codec, reg, mask, value); | 892 | snd_soc_update_bits(dapm->codec, reg, mask, value); |
773 | } | 893 | } |
774 | 894 | ||
775 | list_for_each_entry(w, pending, power_list) { | 895 | list_for_each_entry(w, pending, power_list) { |
776 | /* power up post event */ | 896 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU); |
777 | if (w->power && w->event && | 897 | dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD); |
778 | (w->event_flags & SND_SOC_DAPM_POST_PMU)) { | ||
779 | pop_dbg(codec->pop_time, "pop test : %s POST_PMU\n", | ||
780 | w->name); | ||
781 | ret = w->event(w, | ||
782 | NULL, SND_SOC_DAPM_POST_PMU); | ||
783 | if (ret < 0) | ||
784 | pr_err("%s: post event failed: %d\n", | ||
785 | w->name, ret); | ||
786 | } | ||
787 | |||
788 | /* power down post event */ | ||
789 | if (!w->power && w->event && | ||
790 | (w->event_flags & SND_SOC_DAPM_POST_PMD)) { | ||
791 | pop_dbg(codec->pop_time, "pop test : %s POST_PMD\n", | ||
792 | w->name); | ||
793 | ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); | ||
794 | if (ret < 0) | ||
795 | pr_err("%s: post event failed: %d\n", | ||
796 | w->name, ret); | ||
797 | } | ||
798 | } | 898 | } |
799 | } | 899 | } |
800 | 900 | ||
@@ -806,26 +906,45 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec, | |||
806 | * Currently anything that requires more than a single write is not | 906 | * Currently anything that requires more than a single write is not |
807 | * handled. | 907 | * handled. |
808 | */ | 908 | */ |
809 | static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, | 909 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, |
810 | int event, int sort[]) | 910 | struct list_head *list, int event, bool power_up) |
811 | { | 911 | { |
812 | struct snd_soc_dapm_widget *w, *n; | 912 | struct snd_soc_dapm_widget *w, *n; |
813 | LIST_HEAD(pending); | 913 | LIST_HEAD(pending); |
814 | int cur_sort = -1; | 914 | int cur_sort = -1; |
915 | int cur_subseq = -1; | ||
815 | int cur_reg = SND_SOC_NOPM; | 916 | int cur_reg = SND_SOC_NOPM; |
816 | int ret; | 917 | struct snd_soc_dapm_context *cur_dapm = NULL; |
918 | int ret, i; | ||
919 | int *sort; | ||
920 | |||
921 | if (power_up) | ||
922 | sort = dapm_up_seq; | ||
923 | else | ||
924 | sort = dapm_down_seq; | ||
817 | 925 | ||
818 | list_for_each_entry_safe(w, n, list, power_list) { | 926 | list_for_each_entry_safe(w, n, list, power_list) { |
819 | ret = 0; | 927 | ret = 0; |
820 | 928 | ||
821 | /* Do we need to apply any queued changes? */ | 929 | /* Do we need to apply any queued changes? */ |
822 | if (sort[w->id] != cur_sort || w->reg != cur_reg) { | 930 | if (sort[w->id] != cur_sort || w->reg != cur_reg || |
931 | w->dapm != cur_dapm || w->subseq != cur_subseq) { | ||
823 | if (!list_empty(&pending)) | 932 | if (!list_empty(&pending)) |
824 | dapm_seq_run_coalesced(codec, &pending); | 933 | dapm_seq_run_coalesced(cur_dapm, &pending); |
934 | |||
935 | if (cur_dapm && cur_dapm->seq_notifier) { | ||
936 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | ||
937 | if (sort[i] == cur_sort) | ||
938 | cur_dapm->seq_notifier(cur_dapm, | ||
939 | i, | ||
940 | cur_subseq); | ||
941 | } | ||
825 | 942 | ||
826 | INIT_LIST_HEAD(&pending); | 943 | INIT_LIST_HEAD(&pending); |
827 | cur_sort = -1; | 944 | cur_sort = -1; |
945 | cur_subseq = -1; | ||
828 | cur_reg = SND_SOC_NOPM; | 946 | cur_reg = SND_SOC_NOPM; |
947 | cur_dapm = NULL; | ||
829 | } | 948 | } |
830 | 949 | ||
831 | switch (w->id) { | 950 | switch (w->id) { |
@@ -855,31 +974,120 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, | |||
855 | NULL, SND_SOC_DAPM_POST_PMD); | 974 | NULL, SND_SOC_DAPM_POST_PMD); |
856 | break; | 975 | break; |
857 | 976 | ||
858 | case snd_soc_dapm_input: | ||
859 | case snd_soc_dapm_output: | ||
860 | case snd_soc_dapm_hp: | ||
861 | case snd_soc_dapm_mic: | ||
862 | case snd_soc_dapm_line: | ||
863 | case snd_soc_dapm_spk: | ||
864 | /* No register support currently */ | ||
865 | ret = dapm_generic_apply_power(w); | ||
866 | break; | ||
867 | |||
868 | default: | 977 | default: |
869 | /* Queue it up for application */ | 978 | /* Queue it up for application */ |
870 | cur_sort = sort[w->id]; | 979 | cur_sort = sort[w->id]; |
980 | cur_subseq = w->subseq; | ||
871 | cur_reg = w->reg; | 981 | cur_reg = w->reg; |
982 | cur_dapm = w->dapm; | ||
872 | list_move(&w->power_list, &pending); | 983 | list_move(&w->power_list, &pending); |
873 | break; | 984 | break; |
874 | } | 985 | } |
875 | 986 | ||
876 | if (ret < 0) | 987 | if (ret < 0) |
877 | pr_err("Failed to apply widget power: %d\n", | 988 | dev_err(w->dapm->dev, |
878 | ret); | 989 | "Failed to apply widget power: %d\n", ret); |
879 | } | 990 | } |
880 | 991 | ||
881 | if (!list_empty(&pending)) | 992 | if (!list_empty(&pending)) |
882 | dapm_seq_run_coalesced(codec, &pending); | 993 | dapm_seq_run_coalesced(cur_dapm, &pending); |
994 | |||
995 | if (cur_dapm && cur_dapm->seq_notifier) { | ||
996 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | ||
997 | if (sort[i] == cur_sort) | ||
998 | cur_dapm->seq_notifier(cur_dapm, | ||
999 | i, cur_subseq); | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | ||
1004 | { | ||
1005 | struct snd_soc_dapm_update *update = dapm->update; | ||
1006 | struct snd_soc_dapm_widget *w; | ||
1007 | int ret; | ||
1008 | |||
1009 | if (!update) | ||
1010 | return; | ||
1011 | |||
1012 | w = update->widget; | ||
1013 | |||
1014 | if (w->event && | ||
1015 | (w->event_flags & SND_SOC_DAPM_PRE_REG)) { | ||
1016 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); | ||
1017 | if (ret != 0) | ||
1018 | pr_err("%s DAPM pre-event failed: %d\n", | ||
1019 | w->name, ret); | ||
1020 | } | ||
1021 | |||
1022 | ret = snd_soc_update_bits(w->codec, update->reg, update->mask, | ||
1023 | update->val); | ||
1024 | if (ret < 0) | ||
1025 | pr_err("%s DAPM update failed: %d\n", w->name, ret); | ||
1026 | |||
1027 | if (w->event && | ||
1028 | (w->event_flags & SND_SOC_DAPM_POST_REG)) { | ||
1029 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); | ||
1030 | if (ret != 0) | ||
1031 | pr_err("%s DAPM post-event failed: %d\n", | ||
1032 | w->name, ret); | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | /* Async callback run prior to DAPM sequences - brings to _PREPARE if | ||
1037 | * they're changing state. | ||
1038 | */ | ||
1039 | static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) | ||
1040 | { | ||
1041 | struct snd_soc_dapm_context *d = data; | ||
1042 | int ret; | ||
1043 | |||
1044 | if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) { | ||
1045 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | ||
1046 | if (ret != 0) | ||
1047 | dev_err(d->dev, | ||
1048 | "Failed to turn on bias: %d\n", ret); | ||
1049 | } | ||
1050 | |||
1051 | /* If we're changing to all on or all off then prepare */ | ||
1052 | if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) || | ||
1053 | (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) { | ||
1054 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); | ||
1055 | if (ret != 0) | ||
1056 | dev_err(d->dev, | ||
1057 | "Failed to prepare bias: %d\n", ret); | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | /* Async callback run prior to DAPM sequences - brings to their final | ||
1062 | * state. | ||
1063 | */ | ||
1064 | static void dapm_post_sequence_async(void *data, async_cookie_t cookie) | ||
1065 | { | ||
1066 | struct snd_soc_dapm_context *d = data; | ||
1067 | int ret; | ||
1068 | |||
1069 | /* If we just powered the last thing off drop to standby bias */ | ||
1070 | if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) { | ||
1071 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | ||
1072 | if (ret != 0) | ||
1073 | dev_err(d->dev, "Failed to apply standby bias: %d\n", | ||
1074 | ret); | ||
1075 | } | ||
1076 | |||
1077 | /* If we're in standby and can support bias off then do that */ | ||
1078 | if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) { | ||
1079 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); | ||
1080 | if (ret != 0) | ||
1081 | dev_err(d->dev, "Failed to turn off bias: %d\n", ret); | ||
1082 | } | ||
1083 | |||
1084 | /* If we just powered up then move to active bias */ | ||
1085 | if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) { | ||
1086 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); | ||
1087 | if (ret != 0) | ||
1088 | dev_err(d->dev, "Failed to apply active bias: %d\n", | ||
1089 | ret); | ||
1090 | } | ||
883 | } | 1091 | } |
884 | 1092 | ||
885 | /* | 1093 | /* |
@@ -891,26 +1099,32 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list, | |||
891 | * o Input pin to Output pin (bypass, sidetone) | 1099 | * o Input pin to Output pin (bypass, sidetone) |
892 | * o DAC to ADC (loopback). | 1100 | * o DAC to ADC (loopback). |
893 | */ | 1101 | */ |
894 | static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | 1102 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) |
895 | { | 1103 | { |
896 | struct snd_soc_device *socdev = codec->socdev; | 1104 | struct snd_soc_card *card = dapm->card; |
897 | struct snd_soc_dapm_widget *w; | 1105 | struct snd_soc_dapm_widget *w; |
1106 | struct snd_soc_dapm_context *d; | ||
898 | LIST_HEAD(up_list); | 1107 | LIST_HEAD(up_list); |
899 | LIST_HEAD(down_list); | 1108 | LIST_HEAD(down_list); |
900 | int ret = 0; | 1109 | LIST_HEAD(async_domain); |
901 | int power; | 1110 | int power; |
902 | int sys_power = 0; | 1111 | |
1112 | trace_snd_soc_dapm_start(card); | ||
1113 | |||
1114 | list_for_each_entry(d, &card->dapm_list, list) | ||
1115 | if (d->n_widgets || d->codec == NULL) | ||
1116 | d->dev_power = 0; | ||
903 | 1117 | ||
904 | /* Check which widgets we need to power and store them in | 1118 | /* Check which widgets we need to power and store them in |
905 | * lists indicating if they should be powered up or down. | 1119 | * lists indicating if they should be powered up or down. |
906 | */ | 1120 | */ |
907 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 1121 | list_for_each_entry(w, &card->widgets, list) { |
908 | switch (w->id) { | 1122 | switch (w->id) { |
909 | case snd_soc_dapm_pre: | 1123 | case snd_soc_dapm_pre: |
910 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 1124 | dapm_seq_insert(w, &down_list, false); |
911 | break; | 1125 | break; |
912 | case snd_soc_dapm_post: | 1126 | case snd_soc_dapm_post: |
913 | dapm_seq_insert(w, &up_list, dapm_up_seq); | 1127 | dapm_seq_insert(w, &up_list, true); |
914 | break; | 1128 | break; |
915 | 1129 | ||
916 | default: | 1130 | default: |
@@ -922,15 +1136,17 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
922 | else | 1136 | else |
923 | power = 1; | 1137 | power = 1; |
924 | if (power) | 1138 | if (power) |
925 | sys_power = 1; | 1139 | w->dapm->dev_power = 1; |
926 | 1140 | ||
927 | if (w->power == power) | 1141 | if (w->power == power) |
928 | continue; | 1142 | continue; |
929 | 1143 | ||
1144 | trace_snd_soc_dapm_widget_power(w, power); | ||
1145 | |||
930 | if (power) | 1146 | if (power) |
931 | dapm_seq_insert(w, &up_list, dapm_up_seq); | 1147 | dapm_seq_insert(w, &up_list, true); |
932 | else | 1148 | else |
933 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 1149 | dapm_seq_insert(w, &down_list, false); |
934 | 1150 | ||
935 | w->power = power; | 1151 | w->power = power; |
936 | break; | 1152 | break; |
@@ -940,23 +1156,26 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
940 | /* If there are no DAPM widgets then try to figure out power from the | 1156 | /* If there are no DAPM widgets then try to figure out power from the |
941 | * event type. | 1157 | * event type. |
942 | */ | 1158 | */ |
943 | if (list_empty(&codec->dapm_widgets)) { | 1159 | if (!dapm->n_widgets) { |
944 | switch (event) { | 1160 | switch (event) { |
945 | case SND_SOC_DAPM_STREAM_START: | 1161 | case SND_SOC_DAPM_STREAM_START: |
946 | case SND_SOC_DAPM_STREAM_RESUME: | 1162 | case SND_SOC_DAPM_STREAM_RESUME: |
947 | sys_power = 1; | 1163 | dapm->dev_power = 1; |
1164 | break; | ||
1165 | case SND_SOC_DAPM_STREAM_STOP: | ||
1166 | dapm->dev_power = !!dapm->codec->active; | ||
948 | break; | 1167 | break; |
949 | case SND_SOC_DAPM_STREAM_SUSPEND: | 1168 | case SND_SOC_DAPM_STREAM_SUSPEND: |
950 | sys_power = 0; | 1169 | dapm->dev_power = 0; |
951 | break; | 1170 | break; |
952 | case SND_SOC_DAPM_STREAM_NOP: | 1171 | case SND_SOC_DAPM_STREAM_NOP: |
953 | switch (codec->bias_level) { | 1172 | switch (dapm->bias_level) { |
954 | case SND_SOC_BIAS_STANDBY: | 1173 | case SND_SOC_BIAS_STANDBY: |
955 | case SND_SOC_BIAS_OFF: | 1174 | case SND_SOC_BIAS_OFF: |
956 | sys_power = 0; | 1175 | dapm->dev_power = 0; |
957 | break; | 1176 | break; |
958 | default: | 1177 | default: |
959 | sys_power = 1; | 1178 | dapm->dev_power = 1; |
960 | break; | 1179 | break; |
961 | } | 1180 | } |
962 | break; | 1181 | break; |
@@ -965,55 +1184,40 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
965 | } | 1184 | } |
966 | } | 1185 | } |
967 | 1186 | ||
968 | if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) { | 1187 | /* Force all contexts in the card to the same bias state */ |
969 | ret = snd_soc_dapm_set_bias_level(socdev, | 1188 | power = 0; |
970 | SND_SOC_BIAS_STANDBY); | 1189 | list_for_each_entry(d, &card->dapm_list, list) |
971 | if (ret != 0) | 1190 | if (d->dev_power) |
972 | pr_err("Failed to turn on bias: %d\n", ret); | 1191 | power = 1; |
973 | } | 1192 | list_for_each_entry(d, &card->dapm_list, list) |
1193 | d->dev_power = power; | ||
974 | 1194 | ||
975 | /* If we're changing to all on or all off then prepare */ | 1195 | |
976 | if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || | 1196 | /* Run all the bias changes in parallel */ |
977 | (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { | 1197 | list_for_each_entry(d, &dapm->card->dapm_list, list) |
978 | ret = snd_soc_dapm_set_bias_level(socdev, | 1198 | async_schedule_domain(dapm_pre_sequence_async, d, |
979 | SND_SOC_BIAS_PREPARE); | 1199 | &async_domain); |
980 | if (ret != 0) | 1200 | async_synchronize_full_domain(&async_domain); |
981 | pr_err("Failed to prepare bias: %d\n", ret); | ||
982 | } | ||
983 | 1201 | ||
984 | /* Power down widgets first; try to avoid amplifying pops. */ | 1202 | /* Power down widgets first; try to avoid amplifying pops. */ |
985 | dapm_seq_run(codec, &down_list, event, dapm_down_seq); | 1203 | dapm_seq_run(dapm, &down_list, event, false); |
1204 | |||
1205 | dapm_widget_update(dapm); | ||
986 | 1206 | ||
987 | /* Now power up. */ | 1207 | /* Now power up. */ |
988 | dapm_seq_run(codec, &up_list, event, dapm_up_seq); | 1208 | dapm_seq_run(dapm, &up_list, event, true); |
989 | 1209 | ||
990 | /* If we just powered the last thing off drop to standby bias */ | 1210 | /* Run all the bias changes in parallel */ |
991 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { | 1211 | list_for_each_entry(d, &dapm->card->dapm_list, list) |
992 | ret = snd_soc_dapm_set_bias_level(socdev, | 1212 | async_schedule_domain(dapm_post_sequence_async, d, |
993 | SND_SOC_BIAS_STANDBY); | 1213 | &async_domain); |
994 | if (ret != 0) | 1214 | async_synchronize_full_domain(&async_domain); |
995 | pr_err("Failed to apply standby bias: %d\n", ret); | ||
996 | } | ||
997 | 1215 | ||
998 | /* If we're in standby and can support bias off then do that */ | 1216 | pop_dbg(dapm->dev, card->pop_time, |
999 | if (codec->bias_level == SND_SOC_BIAS_STANDBY && | 1217 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
1000 | codec->idle_bias_off) { | 1218 | pop_wait(card->pop_time); |
1001 | ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); | ||
1002 | if (ret != 0) | ||
1003 | pr_err("Failed to turn off bias: %d\n", ret); | ||
1004 | } | ||
1005 | 1219 | ||
1006 | /* If we just powered up then move to active bias */ | 1220 | trace_snd_soc_dapm_done(card); |
1007 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { | ||
1008 | ret = snd_soc_dapm_set_bias_level(socdev, | ||
1009 | SND_SOC_BIAS_ON); | ||
1010 | if (ret != 0) | ||
1011 | pr_err("Failed to apply active bias: %d\n", ret); | ||
1012 | } | ||
1013 | |||
1014 | pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n", | ||
1015 | codec->pop_time); | ||
1016 | pop_wait(codec->pop_time); | ||
1017 | 1221 | ||
1018 | return 0; | 1222 | return 0; |
1019 | } | 1223 | } |
@@ -1040,9 +1244,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1040 | return -ENOMEM; | 1244 | return -ENOMEM; |
1041 | 1245 | ||
1042 | in = is_connected_input_ep(w); | 1246 | in = is_connected_input_ep(w); |
1043 | dapm_clear_walk(w->codec); | 1247 | dapm_clear_walk(w->dapm); |
1044 | out = is_connected_output_ep(w); | 1248 | out = is_connected_output_ep(w); |
1045 | dapm_clear_walk(w->codec); | 1249 | dapm_clear_walk(w->dapm); |
1046 | 1250 | ||
1047 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", | 1251 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", |
1048 | w->name, w->power ? "On" : "Off", in, out); | 1252 | w->name, w->power ? "On" : "Off", in, out); |
@@ -1065,7 +1269,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1065 | 1269 | ||
1066 | if (p->connect) | 1270 | if (p->connect) |
1067 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1271 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1068 | " in %s %s\n", | 1272 | " in \"%s\" \"%s\"\n", |
1069 | p->name ? p->name : "static", | 1273 | p->name ? p->name : "static", |
1070 | p->source->name); | 1274 | p->source->name); |
1071 | } | 1275 | } |
@@ -1075,7 +1279,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1075 | 1279 | ||
1076 | if (p->connect) | 1280 | if (p->connect) |
1077 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1281 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1078 | " out %s %s\n", | 1282 | " out \"%s\" \"%s\"\n", |
1079 | p->name ? p->name : "static", | 1283 | p->name ? p->name : "static", |
1080 | p->sink->name); | 1284 | p->sink->name); |
1081 | } | 1285 | } |
@@ -1089,33 +1293,107 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1089 | static const struct file_operations dapm_widget_power_fops = { | 1293 | static const struct file_operations dapm_widget_power_fops = { |
1090 | .open = dapm_widget_power_open_file, | 1294 | .open = dapm_widget_power_open_file, |
1091 | .read = dapm_widget_power_read_file, | 1295 | .read = dapm_widget_power_read_file, |
1296 | .llseek = default_llseek, | ||
1092 | }; | 1297 | }; |
1093 | 1298 | ||
1094 | void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) | 1299 | static int dapm_bias_open_file(struct inode *inode, struct file *file) |
1300 | { | ||
1301 | file->private_data = inode->i_private; | ||
1302 | return 0; | ||
1303 | } | ||
1304 | |||
1305 | static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, | ||
1306 | size_t count, loff_t *ppos) | ||
1307 | { | ||
1308 | struct snd_soc_dapm_context *dapm = file->private_data; | ||
1309 | char *level; | ||
1310 | |||
1311 | switch (dapm->bias_level) { | ||
1312 | case SND_SOC_BIAS_ON: | ||
1313 | level = "On\n"; | ||
1314 | break; | ||
1315 | case SND_SOC_BIAS_PREPARE: | ||
1316 | level = "Prepare\n"; | ||
1317 | break; | ||
1318 | case SND_SOC_BIAS_STANDBY: | ||
1319 | level = "Standby\n"; | ||
1320 | break; | ||
1321 | case SND_SOC_BIAS_OFF: | ||
1322 | level = "Off\n"; | ||
1323 | break; | ||
1324 | default: | ||
1325 | BUG(); | ||
1326 | level = "Unknown\n"; | ||
1327 | break; | ||
1328 | } | ||
1329 | |||
1330 | return simple_read_from_buffer(user_buf, count, ppos, level, | ||
1331 | strlen(level)); | ||
1332 | } | ||
1333 | |||
1334 | static const struct file_operations dapm_bias_fops = { | ||
1335 | .open = dapm_bias_open_file, | ||
1336 | .read = dapm_bias_read_file, | ||
1337 | .llseek = default_llseek, | ||
1338 | }; | ||
1339 | |||
1340 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, | ||
1341 | struct dentry *parent) | ||
1095 | { | 1342 | { |
1096 | struct snd_soc_dapm_widget *w; | ||
1097 | struct dentry *d; | 1343 | struct dentry *d; |
1098 | 1344 | ||
1099 | if (!codec->debugfs_dapm) | 1345 | dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); |
1346 | |||
1347 | if (!dapm->debugfs_dapm) { | ||
1348 | printk(KERN_WARNING | ||
1349 | "Failed to create DAPM debugfs directory\n"); | ||
1100 | return; | 1350 | return; |
1351 | } | ||
1101 | 1352 | ||
1102 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 1353 | d = debugfs_create_file("bias_level", 0444, |
1103 | if (!w->name) | 1354 | dapm->debugfs_dapm, dapm, |
1104 | continue; | 1355 | &dapm_bias_fops); |
1356 | if (!d) | ||
1357 | dev_warn(dapm->dev, | ||
1358 | "ASoC: Failed to create bias level debugfs file\n"); | ||
1359 | } | ||
1105 | 1360 | ||
1106 | d = debugfs_create_file(w->name, 0444, | 1361 | static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) |
1107 | codec->debugfs_dapm, w, | 1362 | { |
1108 | &dapm_widget_power_fops); | 1363 | struct snd_soc_dapm_context *dapm = w->dapm; |
1109 | if (!d) | 1364 | struct dentry *d; |
1110 | printk(KERN_WARNING | 1365 | |
1111 | "ASoC: Failed to create %s debugfs file\n", | 1366 | if (!dapm->debugfs_dapm || !w->name) |
1112 | w->name); | 1367 | return; |
1113 | } | 1368 | |
1369 | d = debugfs_create_file(w->name, 0444, | ||
1370 | dapm->debugfs_dapm, w, | ||
1371 | &dapm_widget_power_fops); | ||
1372 | if (!d) | ||
1373 | dev_warn(w->dapm->dev, | ||
1374 | "ASoC: Failed to create %s debugfs file\n", | ||
1375 | w->name); | ||
1114 | } | 1376 | } |
1377 | |||
1378 | static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | ||
1379 | { | ||
1380 | debugfs_remove_recursive(dapm->debugfs_dapm); | ||
1381 | } | ||
1382 | |||
1115 | #else | 1383 | #else |
1116 | void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) | 1384 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, |
1385 | struct dentry *parent) | ||
1386 | { | ||
1387 | } | ||
1388 | |||
1389 | static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) | ||
1390 | { | ||
1391 | } | ||
1392 | |||
1393 | static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | ||
1117 | { | 1394 | { |
1118 | } | 1395 | } |
1396 | |||
1119 | #endif | 1397 | #endif |
1120 | 1398 | ||
1121 | /* test and update the power status of a mux widget */ | 1399 | /* test and update the power status of a mux widget */ |
@@ -1127,6 +1405,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1127 | int found = 0; | 1405 | int found = 0; |
1128 | 1406 | ||
1129 | if (widget->id != snd_soc_dapm_mux && | 1407 | if (widget->id != snd_soc_dapm_mux && |
1408 | widget->id != snd_soc_dapm_virt_mux && | ||
1130 | widget->id != snd_soc_dapm_value_mux) | 1409 | widget->id != snd_soc_dapm_value_mux) |
1131 | return -ENODEV; | 1410 | return -ENODEV; |
1132 | 1411 | ||
@@ -1134,7 +1413,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1134 | return 0; | 1413 | return 0; |
1135 | 1414 | ||
1136 | /* find dapm widget path assoc with kcontrol */ | 1415 | /* find dapm widget path assoc with kcontrol */ |
1137 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | 1416 | list_for_each_entry(path, &widget->dapm->card->paths, list) { |
1138 | if (path->kcontrol != kcontrol) | 1417 | if (path->kcontrol != kcontrol) |
1139 | continue; | 1418 | continue; |
1140 | 1419 | ||
@@ -1150,7 +1429,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1150 | } | 1429 | } |
1151 | 1430 | ||
1152 | if (found) | 1431 | if (found) |
1153 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1432 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); |
1154 | 1433 | ||
1155 | return 0; | 1434 | return 0; |
1156 | } | 1435 | } |
@@ -1168,7 +1447,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1168 | return -ENODEV; | 1447 | return -ENODEV; |
1169 | 1448 | ||
1170 | /* find dapm widget path assoc with kcontrol */ | 1449 | /* find dapm widget path assoc with kcontrol */ |
1171 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | 1450 | list_for_each_entry(path, &widget->dapm->card->paths, list) { |
1172 | if (path->kcontrol != kcontrol) | 1451 | if (path->kcontrol != kcontrol) |
1173 | continue; | 1452 | continue; |
1174 | 1453 | ||
@@ -1179,7 +1458,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1179 | } | 1458 | } |
1180 | 1459 | ||
1181 | if (found) | 1460 | if (found) |
1182 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1461 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); |
1183 | 1462 | ||
1184 | return 0; | 1463 | return 0; |
1185 | } | 1464 | } |
@@ -1188,13 +1467,16 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1188 | static ssize_t dapm_widget_show(struct device *dev, | 1467 | static ssize_t dapm_widget_show(struct device *dev, |
1189 | struct device_attribute *attr, char *buf) | 1468 | struct device_attribute *attr, char *buf) |
1190 | { | 1469 | { |
1191 | struct snd_soc_device *devdata = dev_get_drvdata(dev); | 1470 | struct snd_soc_pcm_runtime *rtd = |
1192 | struct snd_soc_codec *codec = devdata->card->codec; | 1471 | container_of(dev, struct snd_soc_pcm_runtime, dev); |
1472 | struct snd_soc_codec *codec =rtd->codec; | ||
1193 | struct snd_soc_dapm_widget *w; | 1473 | struct snd_soc_dapm_widget *w; |
1194 | int count = 0; | 1474 | int count = 0; |
1195 | char *state = "not set"; | 1475 | char *state = "not set"; |
1196 | 1476 | ||
1197 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 1477 | list_for_each_entry(w, &codec->card->widgets, list) { |
1478 | if (w->dapm != &codec->dapm) | ||
1479 | continue; | ||
1198 | 1480 | ||
1199 | /* only display widgets that burnm power */ | 1481 | /* only display widgets that burnm power */ |
1200 | switch (w->id) { | 1482 | switch (w->id) { |
@@ -1206,6 +1488,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
1206 | case snd_soc_dapm_dac: | 1488 | case snd_soc_dapm_dac: |
1207 | case snd_soc_dapm_adc: | 1489 | case snd_soc_dapm_adc: |
1208 | case snd_soc_dapm_pga: | 1490 | case snd_soc_dapm_pga: |
1491 | case snd_soc_dapm_out_drv: | ||
1209 | case snd_soc_dapm_mixer: | 1492 | case snd_soc_dapm_mixer: |
1210 | case snd_soc_dapm_mixer_named_ctl: | 1493 | case snd_soc_dapm_mixer_named_ctl: |
1211 | case snd_soc_dapm_supply: | 1494 | case snd_soc_dapm_supply: |
@@ -1218,7 +1501,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
1218 | } | 1501 | } |
1219 | } | 1502 | } |
1220 | 1503 | ||
1221 | switch (codec->bias_level) { | 1504 | switch (codec->dapm.bias_level) { |
1222 | case SND_SOC_BIAS_ON: | 1505 | case SND_SOC_BIAS_ON: |
1223 | state = "On"; | 1506 | state = "On"; |
1224 | break; | 1507 | break; |
@@ -1250,79 +1533,141 @@ static void snd_soc_dapm_sys_remove(struct device *dev) | |||
1250 | } | 1533 | } |
1251 | 1534 | ||
1252 | /* free all dapm widgets and resources */ | 1535 | /* free all dapm widgets and resources */ |
1253 | static void dapm_free_widgets(struct snd_soc_codec *codec) | 1536 | static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) |
1254 | { | 1537 | { |
1255 | struct snd_soc_dapm_widget *w, *next_w; | 1538 | struct snd_soc_dapm_widget *w, *next_w; |
1256 | struct snd_soc_dapm_path *p, *next_p; | 1539 | struct snd_soc_dapm_path *p, *next_p; |
1257 | 1540 | ||
1258 | list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) { | 1541 | list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { |
1542 | if (w->dapm != dapm) | ||
1543 | continue; | ||
1259 | list_del(&w->list); | 1544 | list_del(&w->list); |
1545 | /* | ||
1546 | * remove source and sink paths associated to this widget. | ||
1547 | * While removing the path, remove reference to it from both | ||
1548 | * source and sink widgets so that path is removed only once. | ||
1549 | */ | ||
1550 | list_for_each_entry_safe(p, next_p, &w->sources, list_sink) { | ||
1551 | list_del(&p->list_sink); | ||
1552 | list_del(&p->list_source); | ||
1553 | list_del(&p->list); | ||
1554 | kfree(p->long_name); | ||
1555 | kfree(p); | ||
1556 | } | ||
1557 | list_for_each_entry_safe(p, next_p, &w->sinks, list_source) { | ||
1558 | list_del(&p->list_sink); | ||
1559 | list_del(&p->list_source); | ||
1560 | list_del(&p->list); | ||
1561 | kfree(p->long_name); | ||
1562 | kfree(p); | ||
1563 | } | ||
1564 | kfree(w->kcontrols); | ||
1565 | kfree(w->name); | ||
1260 | kfree(w); | 1566 | kfree(w); |
1261 | } | 1567 | } |
1262 | |||
1263 | list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) { | ||
1264 | list_del(&p->list); | ||
1265 | kfree(p->long_name); | ||
1266 | kfree(p); | ||
1267 | } | ||
1268 | } | 1568 | } |
1269 | 1569 | ||
1270 | static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | 1570 | static struct snd_soc_dapm_widget *dapm_find_widget( |
1271 | const char *pin, int status) | 1571 | struct snd_soc_dapm_context *dapm, const char *pin, |
1572 | bool search_other_contexts) | ||
1272 | { | 1573 | { |
1273 | struct snd_soc_dapm_widget *w; | 1574 | struct snd_soc_dapm_widget *w; |
1575 | struct snd_soc_dapm_widget *fallback = NULL; | ||
1274 | 1576 | ||
1275 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 1577 | list_for_each_entry(w, &dapm->card->widgets, list) { |
1276 | if (!strcmp(w->name, pin)) { | 1578 | if (!strcmp(w->name, pin)) { |
1277 | pr_debug("dapm: %s: pin %s\n", codec->name, pin); | 1579 | if (w->dapm == dapm) |
1278 | w->connected = status; | 1580 | return w; |
1279 | /* Allow disabling of forced pins */ | 1581 | else |
1280 | if (status == 0) | 1582 | fallback = w; |
1281 | w->force = 0; | ||
1282 | return 0; | ||
1283 | } | 1583 | } |
1284 | } | 1584 | } |
1285 | 1585 | ||
1286 | pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin); | 1586 | if (search_other_contexts) |
1287 | return -EINVAL; | 1587 | return fallback; |
1588 | |||
1589 | return NULL; | ||
1590 | } | ||
1591 | |||
1592 | static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | ||
1593 | const char *pin, int status) | ||
1594 | { | ||
1595 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); | ||
1596 | |||
1597 | if (!w) { | ||
1598 | dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); | ||
1599 | return -EINVAL; | ||
1600 | } | ||
1601 | |||
1602 | w->connected = status; | ||
1603 | if (status == 0) | ||
1604 | w->force = 0; | ||
1605 | |||
1606 | return 0; | ||
1288 | } | 1607 | } |
1289 | 1608 | ||
1290 | /** | 1609 | /** |
1291 | * snd_soc_dapm_sync - scan and power dapm paths | 1610 | * snd_soc_dapm_sync - scan and power dapm paths |
1292 | * @codec: audio codec | 1611 | * @dapm: DAPM context |
1293 | * | 1612 | * |
1294 | * Walks all dapm audio paths and powers widgets according to their | 1613 | * Walks all dapm audio paths and powers widgets according to their |
1295 | * stream or path usage. | 1614 | * stream or path usage. |
1296 | * | 1615 | * |
1297 | * Returns 0 for success. | 1616 | * Returns 0 for success. |
1298 | */ | 1617 | */ |
1299 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) | 1618 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) |
1300 | { | 1619 | { |
1301 | return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 1620 | return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); |
1302 | } | 1621 | } |
1303 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 1622 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1304 | 1623 | ||
1305 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | 1624 | static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, |
1306 | const struct snd_soc_dapm_route *route) | 1625 | const struct snd_soc_dapm_route *route) |
1307 | { | 1626 | { |
1308 | struct snd_soc_dapm_path *path; | 1627 | struct snd_soc_dapm_path *path; |
1309 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 1628 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
1310 | const char *sink = route->sink; | 1629 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; |
1630 | const char *sink; | ||
1311 | const char *control = route->control; | 1631 | const char *control = route->control; |
1312 | const char *source = route->source; | 1632 | const char *source; |
1633 | char prefixed_sink[80]; | ||
1634 | char prefixed_source[80]; | ||
1313 | int ret = 0; | 1635 | int ret = 0; |
1314 | 1636 | ||
1315 | /* find src and dest widgets */ | 1637 | if (dapm->codec && dapm->codec->name_prefix) { |
1316 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 1638 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
1639 | dapm->codec->name_prefix, route->sink); | ||
1640 | sink = prefixed_sink; | ||
1641 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | ||
1642 | dapm->codec->name_prefix, route->source); | ||
1643 | source = prefixed_source; | ||
1644 | } else { | ||
1645 | sink = route->sink; | ||
1646 | source = route->source; | ||
1647 | } | ||
1317 | 1648 | ||
1649 | /* | ||
1650 | * find src and dest widgets over all widgets but favor a widget from | ||
1651 | * current DAPM context | ||
1652 | */ | ||
1653 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
1318 | if (!wsink && !(strcmp(w->name, sink))) { | 1654 | if (!wsink && !(strcmp(w->name, sink))) { |
1319 | wsink = w; | 1655 | wtsink = w; |
1656 | if (w->dapm == dapm) | ||
1657 | wsink = w; | ||
1320 | continue; | 1658 | continue; |
1321 | } | 1659 | } |
1322 | if (!wsource && !(strcmp(w->name, source))) { | 1660 | if (!wsource && !(strcmp(w->name, source))) { |
1323 | wsource = w; | 1661 | wtsource = w; |
1662 | if (w->dapm == dapm) | ||
1663 | wsource = w; | ||
1324 | } | 1664 | } |
1325 | } | 1665 | } |
1666 | /* use widget from another DAPM context if not found from this */ | ||
1667 | if (!wsink) | ||
1668 | wsink = wtsink; | ||
1669 | if (!wsource) | ||
1670 | wsource = wtsource; | ||
1326 | 1671 | ||
1327 | if (wsource == NULL || wsink == NULL) | 1672 | if (wsource == NULL || wsink == NULL) |
1328 | return -ENODEV; | 1673 | return -ENODEV; |
@@ -1356,7 +1701,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1356 | 1701 | ||
1357 | /* connect static paths */ | 1702 | /* connect static paths */ |
1358 | if (control == NULL) { | 1703 | if (control == NULL) { |
1359 | list_add(&path->list, &codec->dapm_paths); | 1704 | list_add(&path->list, &dapm->card->paths); |
1360 | list_add(&path->list_sink, &wsink->sources); | 1705 | list_add(&path->list_sink, &wsink->sources); |
1361 | list_add(&path->list_source, &wsource->sinks); | 1706 | list_add(&path->list_source, &wsource->sinks); |
1362 | path->connect = 1; | 1707 | path->connect = 1; |
@@ -1364,10 +1709,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1364 | } | 1709 | } |
1365 | 1710 | ||
1366 | /* connect dynamic paths */ | 1711 | /* connect dynamic paths */ |
1367 | switch(wsink->id) { | 1712 | switch (wsink->id) { |
1368 | case snd_soc_dapm_adc: | 1713 | case snd_soc_dapm_adc: |
1369 | case snd_soc_dapm_dac: | 1714 | case snd_soc_dapm_dac: |
1370 | case snd_soc_dapm_pga: | 1715 | case snd_soc_dapm_pga: |
1716 | case snd_soc_dapm_out_drv: | ||
1371 | case snd_soc_dapm_input: | 1717 | case snd_soc_dapm_input: |
1372 | case snd_soc_dapm_output: | 1718 | case snd_soc_dapm_output: |
1373 | case snd_soc_dapm_micbias: | 1719 | case snd_soc_dapm_micbias: |
@@ -1377,22 +1723,23 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1377 | case snd_soc_dapm_supply: | 1723 | case snd_soc_dapm_supply: |
1378 | case snd_soc_dapm_aif_in: | 1724 | case snd_soc_dapm_aif_in: |
1379 | case snd_soc_dapm_aif_out: | 1725 | case snd_soc_dapm_aif_out: |
1380 | list_add(&path->list, &codec->dapm_paths); | 1726 | list_add(&path->list, &dapm->card->paths); |
1381 | list_add(&path->list_sink, &wsink->sources); | 1727 | list_add(&path->list_sink, &wsink->sources); |
1382 | list_add(&path->list_source, &wsource->sinks); | 1728 | list_add(&path->list_source, &wsource->sinks); |
1383 | path->connect = 1; | 1729 | path->connect = 1; |
1384 | return 0; | 1730 | return 0; |
1385 | case snd_soc_dapm_mux: | 1731 | case snd_soc_dapm_mux: |
1732 | case snd_soc_dapm_virt_mux: | ||
1386 | case snd_soc_dapm_value_mux: | 1733 | case snd_soc_dapm_value_mux: |
1387 | ret = dapm_connect_mux(codec, wsource, wsink, path, control, | 1734 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, |
1388 | &wsink->kcontrols[0]); | 1735 | &wsink->kcontrol_news[0]); |
1389 | if (ret != 0) | 1736 | if (ret != 0) |
1390 | goto err; | 1737 | goto err; |
1391 | break; | 1738 | break; |
1392 | case snd_soc_dapm_switch: | 1739 | case snd_soc_dapm_switch: |
1393 | case snd_soc_dapm_mixer: | 1740 | case snd_soc_dapm_mixer: |
1394 | case snd_soc_dapm_mixer_named_ctl: | 1741 | case snd_soc_dapm_mixer_named_ctl: |
1395 | ret = dapm_connect_mixer(codec, wsource, wsink, path, control); | 1742 | ret = dapm_connect_mixer(dapm, wsource, wsink, path, control); |
1396 | if (ret != 0) | 1743 | if (ret != 0) |
1397 | goto err; | 1744 | goto err; |
1398 | break; | 1745 | break; |
@@ -1400,7 +1747,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1400 | case snd_soc_dapm_mic: | 1747 | case snd_soc_dapm_mic: |
1401 | case snd_soc_dapm_line: | 1748 | case snd_soc_dapm_line: |
1402 | case snd_soc_dapm_spk: | 1749 | case snd_soc_dapm_spk: |
1403 | list_add(&path->list, &codec->dapm_paths); | 1750 | list_add(&path->list, &dapm->card->paths); |
1404 | list_add(&path->list_sink, &wsink->sources); | 1751 | list_add(&path->list_sink, &wsink->sources); |
1405 | list_add(&path->list_source, &wsource->sinks); | 1752 | list_add(&path->list_source, &wsource->sinks); |
1406 | path->connect = 0; | 1753 | path->connect = 0; |
@@ -1409,15 +1756,15 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1409 | return 0; | 1756 | return 0; |
1410 | 1757 | ||
1411 | err: | 1758 | err: |
1412 | printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source, | 1759 | dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n", |
1413 | control, sink); | 1760 | source, control, sink); |
1414 | kfree(path); | 1761 | kfree(path); |
1415 | return ret; | 1762 | return ret; |
1416 | } | 1763 | } |
1417 | 1764 | ||
1418 | /** | 1765 | /** |
1419 | * snd_soc_dapm_add_routes - Add routes between DAPM widgets | 1766 | * snd_soc_dapm_add_routes - Add routes between DAPM widgets |
1420 | * @codec: codec | 1767 | * @dapm: DAPM context |
1421 | * @route: audio routes | 1768 | * @route: audio routes |
1422 | * @num: number of routes | 1769 | * @num: number of routes |
1423 | * | 1770 | * |
@@ -1428,17 +1775,16 @@ err: | |||
1428 | * Returns 0 for success else error. On error all resources can be freed | 1775 | * Returns 0 for success else error. On error all resources can be freed |
1429 | * with a call to snd_soc_card_free(). | 1776 | * with a call to snd_soc_card_free(). |
1430 | */ | 1777 | */ |
1431 | int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | 1778 | int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, |
1432 | const struct snd_soc_dapm_route *route, int num) | 1779 | const struct snd_soc_dapm_route *route, int num) |
1433 | { | 1780 | { |
1434 | int i, ret; | 1781 | int i, ret; |
1435 | 1782 | ||
1436 | for (i = 0; i < num; i++) { | 1783 | for (i = 0; i < num; i++) { |
1437 | ret = snd_soc_dapm_add_route(codec, route); | 1784 | ret = snd_soc_dapm_add_route(dapm, route); |
1438 | if (ret < 0) { | 1785 | if (ret < 0) { |
1439 | printk(KERN_ERR "Failed to add route %s->%s\n", | 1786 | dev_err(dapm->dev, "Failed to add route %s->%s\n", |
1440 | route->source, | 1787 | route->source, route->sink); |
1441 | route->sink); | ||
1442 | return ret; | 1788 | return ret; |
1443 | } | 1789 | } |
1444 | route++; | 1790 | route++; |
@@ -1450,32 +1796,42 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); | |||
1450 | 1796 | ||
1451 | /** | 1797 | /** |
1452 | * snd_soc_dapm_new_widgets - add new dapm widgets | 1798 | * snd_soc_dapm_new_widgets - add new dapm widgets |
1453 | * @codec: audio codec | 1799 | * @dapm: DAPM context |
1454 | * | 1800 | * |
1455 | * Checks the codec for any new dapm widgets and creates them if found. | 1801 | * Checks the codec for any new dapm widgets and creates them if found. |
1456 | * | 1802 | * |
1457 | * Returns 0 for success. | 1803 | * Returns 0 for success. |
1458 | */ | 1804 | */ |
1459 | int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | 1805 | int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) |
1460 | { | 1806 | { |
1461 | struct snd_soc_dapm_widget *w; | 1807 | struct snd_soc_dapm_widget *w; |
1808 | unsigned int val; | ||
1462 | 1809 | ||
1463 | list_for_each_entry(w, &codec->dapm_widgets, list) | 1810 | list_for_each_entry(w, &dapm->card->widgets, list) |
1464 | { | 1811 | { |
1465 | if (w->new) | 1812 | if (w->new) |
1466 | continue; | 1813 | continue; |
1467 | 1814 | ||
1815 | if (w->num_kcontrols) { | ||
1816 | w->kcontrols = kzalloc(w->num_kcontrols * | ||
1817 | sizeof(struct snd_kcontrol *), | ||
1818 | GFP_KERNEL); | ||
1819 | if (!w->kcontrols) | ||
1820 | return -ENOMEM; | ||
1821 | } | ||
1822 | |||
1468 | switch(w->id) { | 1823 | switch(w->id) { |
1469 | case snd_soc_dapm_switch: | 1824 | case snd_soc_dapm_switch: |
1470 | case snd_soc_dapm_mixer: | 1825 | case snd_soc_dapm_mixer: |
1471 | case snd_soc_dapm_mixer_named_ctl: | 1826 | case snd_soc_dapm_mixer_named_ctl: |
1472 | w->power_check = dapm_generic_check_power; | 1827 | w->power_check = dapm_generic_check_power; |
1473 | dapm_new_mixer(codec, w); | 1828 | dapm_new_mixer(w); |
1474 | break; | 1829 | break; |
1475 | case snd_soc_dapm_mux: | 1830 | case snd_soc_dapm_mux: |
1831 | case snd_soc_dapm_virt_mux: | ||
1476 | case snd_soc_dapm_value_mux: | 1832 | case snd_soc_dapm_value_mux: |
1477 | w->power_check = dapm_generic_check_power; | 1833 | w->power_check = dapm_generic_check_power; |
1478 | dapm_new_mux(codec, w); | 1834 | dapm_new_mux(w); |
1479 | break; | 1835 | break; |
1480 | case snd_soc_dapm_adc: | 1836 | case snd_soc_dapm_adc: |
1481 | case snd_soc_dapm_aif_out: | 1837 | case snd_soc_dapm_aif_out: |
@@ -1486,8 +1842,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
1486 | w->power_check = dapm_dac_check_power; | 1842 | w->power_check = dapm_dac_check_power; |
1487 | break; | 1843 | break; |
1488 | case snd_soc_dapm_pga: | 1844 | case snd_soc_dapm_pga: |
1845 | case snd_soc_dapm_out_drv: | ||
1489 | w->power_check = dapm_generic_check_power; | 1846 | w->power_check = dapm_generic_check_power; |
1490 | dapm_new_pga(codec, w); | 1847 | dapm_new_pga(w); |
1491 | break; | 1848 | break; |
1492 | case snd_soc_dapm_input: | 1849 | case snd_soc_dapm_input: |
1493 | case snd_soc_dapm_output: | 1850 | case snd_soc_dapm_output: |
@@ -1505,10 +1862,24 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
1505 | case snd_soc_dapm_post: | 1862 | case snd_soc_dapm_post: |
1506 | break; | 1863 | break; |
1507 | } | 1864 | } |
1865 | |||
1866 | /* Read the initial power state from the device */ | ||
1867 | if (w->reg >= 0) { | ||
1868 | val = snd_soc_read(w->codec, w->reg); | ||
1869 | val &= 1 << w->shift; | ||
1870 | if (w->invert) | ||
1871 | val = !val; | ||
1872 | |||
1873 | if (val) | ||
1874 | w->power = 1; | ||
1875 | } | ||
1876 | |||
1508 | w->new = 1; | 1877 | w->new = 1; |
1878 | |||
1879 | dapm_debugfs_add_widget(w); | ||
1509 | } | 1880 | } |
1510 | 1881 | ||
1511 | dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 1882 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); |
1512 | return 0; | 1883 | return 0; |
1513 | } | 1884 | } |
1514 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | 1885 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); |
@@ -1525,7 +1896,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
1525 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | 1896 | int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, |
1526 | struct snd_ctl_elem_value *ucontrol) | 1897 | struct snd_ctl_elem_value *ucontrol) |
1527 | { | 1898 | { |
1528 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1899 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
1900 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1529 | struct soc_mixer_control *mc = | 1901 | struct soc_mixer_control *mc = |
1530 | (struct soc_mixer_control *)kcontrol->private_value; | 1902 | (struct soc_mixer_control *)kcontrol->private_value; |
1531 | unsigned int reg = mc->reg; | 1903 | unsigned int reg = mc->reg; |
@@ -1564,66 +1936,59 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
1564 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | 1936 | int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, |
1565 | struct snd_ctl_elem_value *ucontrol) | 1937 | struct snd_ctl_elem_value *ucontrol) |
1566 | { | 1938 | { |
1567 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1939 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
1940 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1941 | struct snd_soc_codec *codec = widget->codec; | ||
1568 | struct soc_mixer_control *mc = | 1942 | struct soc_mixer_control *mc = |
1569 | (struct soc_mixer_control *)kcontrol->private_value; | 1943 | (struct soc_mixer_control *)kcontrol->private_value; |
1570 | unsigned int reg = mc->reg; | 1944 | unsigned int reg = mc->reg; |
1571 | unsigned int shift = mc->shift; | 1945 | unsigned int shift = mc->shift; |
1572 | unsigned int rshift = mc->rshift; | ||
1573 | int max = mc->max; | 1946 | int max = mc->max; |
1574 | unsigned int mask = (1 << fls(max)) - 1; | 1947 | unsigned int mask = (1 << fls(max)) - 1; |
1575 | unsigned int invert = mc->invert; | 1948 | unsigned int invert = mc->invert; |
1576 | unsigned int val, val2, val_mask; | 1949 | unsigned int val; |
1577 | int connect; | 1950 | int connect, change; |
1578 | int ret; | 1951 | struct snd_soc_dapm_update update; |
1952 | int wi; | ||
1579 | 1953 | ||
1580 | val = (ucontrol->value.integer.value[0] & mask); | 1954 | val = (ucontrol->value.integer.value[0] & mask); |
1581 | 1955 | ||
1582 | if (invert) | 1956 | if (invert) |
1583 | val = max - val; | 1957 | val = max - val; |
1584 | val_mask = mask << shift; | 1958 | mask = mask << shift; |
1585 | val = val << shift; | 1959 | val = val << shift; |
1586 | if (shift != rshift) { | ||
1587 | val2 = (ucontrol->value.integer.value[1] & mask); | ||
1588 | if (invert) | ||
1589 | val2 = max - val2; | ||
1590 | val_mask |= mask << rshift; | ||
1591 | val |= val2 << rshift; | ||
1592 | } | ||
1593 | 1960 | ||
1594 | mutex_lock(&widget->codec->mutex); | 1961 | if (val) |
1595 | widget->value = val; | 1962 | /* new connection */ |
1963 | connect = invert ? 0 : 1; | ||
1964 | else | ||
1965 | /* old connection must be powered down */ | ||
1966 | connect = invert ? 1 : 0; | ||
1596 | 1967 | ||
1597 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { | 1968 | mutex_lock(&codec->mutex); |
1598 | if (val) | ||
1599 | /* new connection */ | ||
1600 | connect = invert ? 0:1; | ||
1601 | else | ||
1602 | /* old connection must be powered down */ | ||
1603 | connect = invert ? 1:0; | ||
1604 | 1969 | ||
1605 | dapm_mixer_update_power(widget, kcontrol, connect); | 1970 | change = snd_soc_test_bits(widget->codec, reg, mask, val); |
1606 | } | 1971 | if (change) { |
1972 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
1973 | widget = wlist->widgets[wi]; | ||
1607 | 1974 | ||
1608 | if (widget->event) { | 1975 | widget->value = val; |
1609 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1976 | |
1610 | ret = widget->event(widget, kcontrol, | 1977 | update.kcontrol = kcontrol; |
1611 | SND_SOC_DAPM_PRE_REG); | 1978 | update.widget = widget; |
1612 | if (ret < 0) { | 1979 | update.reg = reg; |
1613 | ret = 1; | 1980 | update.mask = mask; |
1614 | goto out; | 1981 | update.val = val; |
1615 | } | 1982 | widget->dapm->update = &update; |
1983 | |||
1984 | dapm_mixer_update_power(widget, kcontrol, connect); | ||
1985 | |||
1986 | widget->dapm->update = NULL; | ||
1616 | } | 1987 | } |
1617 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 1988 | } |
1618 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1989 | |
1619 | ret = widget->event(widget, kcontrol, | 1990 | mutex_unlock(&codec->mutex); |
1620 | SND_SOC_DAPM_POST_REG); | 1991 | return 0; |
1621 | } else | ||
1622 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | ||
1623 | |||
1624 | out: | ||
1625 | mutex_unlock(&widget->codec->mutex); | ||
1626 | return ret; | ||
1627 | } | 1992 | } |
1628 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | 1993 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); |
1629 | 1994 | ||
@@ -1639,7 +2004,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
1639 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | 2004 | int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, |
1640 | struct snd_ctl_elem_value *ucontrol) | 2005 | struct snd_ctl_elem_value *ucontrol) |
1641 | { | 2006 | { |
1642 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2007 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2008 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1643 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2009 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1644 | unsigned int val, bitmask; | 2010 | unsigned int val, bitmask; |
1645 | 2011 | ||
@@ -1667,11 +2033,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
1667 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 2033 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
1668 | struct snd_ctl_elem_value *ucontrol) | 2034 | struct snd_ctl_elem_value *ucontrol) |
1669 | { | 2035 | { |
1670 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2036 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2037 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2038 | struct snd_soc_codec *codec = widget->codec; | ||
1671 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2039 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1672 | unsigned int val, mux, change; | 2040 | unsigned int val, mux, change; |
1673 | unsigned int mask, bitmask; | 2041 | unsigned int mask, bitmask; |
1674 | int ret = 0; | 2042 | struct snd_soc_dapm_update update; |
2043 | int wi; | ||
1675 | 2044 | ||
1676 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 2045 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1677 | ; | 2046 | ; |
@@ -1687,27 +2056,30 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1687 | mask |= (bitmask - 1) << e->shift_r; | 2056 | mask |= (bitmask - 1) << e->shift_r; |
1688 | } | 2057 | } |
1689 | 2058 | ||
1690 | mutex_lock(&widget->codec->mutex); | 2059 | mutex_lock(&codec->mutex); |
1691 | widget->value = val; | 2060 | |
1692 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2061 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1693 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2062 | if (change) { |
2063 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
2064 | widget = wlist->widgets[wi]; | ||
1694 | 2065 | ||
1695 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 2066 | widget->value = val; |
1696 | ret = widget->event(widget, | ||
1697 | kcontrol, SND_SOC_DAPM_PRE_REG); | ||
1698 | if (ret < 0) | ||
1699 | goto out; | ||
1700 | } | ||
1701 | 2067 | ||
1702 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 2068 | update.kcontrol = kcontrol; |
2069 | update.widget = widget; | ||
2070 | update.reg = e->reg; | ||
2071 | update.mask = mask; | ||
2072 | update.val = val; | ||
2073 | widget->dapm->update = &update; | ||
1703 | 2074 | ||
1704 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 2075 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1705 | ret = widget->event(widget, | ||
1706 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1707 | 2076 | ||
1708 | out: | 2077 | widget->dapm->update = NULL; |
1709 | mutex_unlock(&widget->codec->mutex); | 2078 | } |
1710 | return ret; | 2079 | } |
2080 | |||
2081 | mutex_unlock(&codec->mutex); | ||
2082 | return change; | ||
1711 | } | 2083 | } |
1712 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 2084 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
1713 | 2085 | ||
@@ -1721,7 +2093,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | |||
1721 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | 2093 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, |
1722 | struct snd_ctl_elem_value *ucontrol) | 2094 | struct snd_ctl_elem_value *ucontrol) |
1723 | { | 2095 | { |
1724 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2096 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2097 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1725 | 2098 | ||
1726 | ucontrol->value.enumerated.item[0] = widget->value; | 2099 | ucontrol->value.enumerated.item[0] = widget->value; |
1727 | 2100 | ||
@@ -1739,22 +2112,33 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | |||
1739 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | 2112 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, |
1740 | struct snd_ctl_elem_value *ucontrol) | 2113 | struct snd_ctl_elem_value *ucontrol) |
1741 | { | 2114 | { |
1742 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2115 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2116 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2117 | struct snd_soc_codec *codec = widget->codec; | ||
1743 | struct soc_enum *e = | 2118 | struct soc_enum *e = |
1744 | (struct soc_enum *)kcontrol->private_value; | 2119 | (struct soc_enum *)kcontrol->private_value; |
1745 | int change; | 2120 | int change; |
1746 | int ret = 0; | 2121 | int ret = 0; |
2122 | int wi; | ||
1747 | 2123 | ||
1748 | if (ucontrol->value.enumerated.item[0] >= e->max) | 2124 | if (ucontrol->value.enumerated.item[0] >= e->max) |
1749 | return -EINVAL; | 2125 | return -EINVAL; |
1750 | 2126 | ||
1751 | mutex_lock(&widget->codec->mutex); | 2127 | mutex_lock(&codec->mutex); |
1752 | 2128 | ||
1753 | change = widget->value != ucontrol->value.enumerated.item[0]; | 2129 | change = widget->value != ucontrol->value.enumerated.item[0]; |
1754 | widget->value = ucontrol->value.enumerated.item[0]; | 2130 | if (change) { |
1755 | dapm_mux_update_power(widget, kcontrol, change, widget->value, e); | 2131 | for (wi = 0; wi < wlist->num_widgets; wi++) { |
2132 | widget = wlist->widgets[wi]; | ||
1756 | 2133 | ||
1757 | mutex_unlock(&widget->codec->mutex); | 2134 | widget->value = ucontrol->value.enumerated.item[0]; |
2135 | |||
2136 | dapm_mux_update_power(widget, kcontrol, change, | ||
2137 | widget->value, e); | ||
2138 | } | ||
2139 | } | ||
2140 | |||
2141 | mutex_unlock(&codec->mutex); | ||
1758 | return ret; | 2142 | return ret; |
1759 | } | 2143 | } |
1760 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | 2144 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); |
@@ -1775,7 +2159,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | |||
1775 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | 2159 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, |
1776 | struct snd_ctl_elem_value *ucontrol) | 2160 | struct snd_ctl_elem_value *ucontrol) |
1777 | { | 2161 | { |
1778 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2162 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2163 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
1779 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2164 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1780 | unsigned int reg_val, val, mux; | 2165 | unsigned int reg_val, val, mux; |
1781 | 2166 | ||
@@ -1815,11 +2200,14 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | |||
1815 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 2200 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, |
1816 | struct snd_ctl_elem_value *ucontrol) | 2201 | struct snd_ctl_elem_value *ucontrol) |
1817 | { | 2202 | { |
1818 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 2203 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2204 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | ||
2205 | struct snd_soc_codec *codec = widget->codec; | ||
1819 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2206 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1820 | unsigned int val, mux, change; | 2207 | unsigned int val, mux, change; |
1821 | unsigned int mask; | 2208 | unsigned int mask; |
1822 | int ret = 0; | 2209 | struct snd_soc_dapm_update update; |
2210 | int wi; | ||
1823 | 2211 | ||
1824 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2212 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
1825 | return -EINVAL; | 2213 | return -EINVAL; |
@@ -1833,27 +2221,30 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1833 | mask |= e->mask << e->shift_r; | 2221 | mask |= e->mask << e->shift_r; |
1834 | } | 2222 | } |
1835 | 2223 | ||
1836 | mutex_lock(&widget->codec->mutex); | 2224 | mutex_lock(&codec->mutex); |
1837 | widget->value = val; | 2225 | |
1838 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2226 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1839 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2227 | if (change) { |
2228 | for (wi = 0; wi < wlist->num_widgets; wi++) { | ||
2229 | widget = wlist->widgets[wi]; | ||
1840 | 2230 | ||
1841 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 2231 | widget->value = val; |
1842 | ret = widget->event(widget, | ||
1843 | kcontrol, SND_SOC_DAPM_PRE_REG); | ||
1844 | if (ret < 0) | ||
1845 | goto out; | ||
1846 | } | ||
1847 | 2232 | ||
1848 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 2233 | update.kcontrol = kcontrol; |
2234 | update.widget = widget; | ||
2235 | update.reg = e->reg; | ||
2236 | update.mask = mask; | ||
2237 | update.val = val; | ||
2238 | widget->dapm->update = &update; | ||
1849 | 2239 | ||
1850 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 2240 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1851 | ret = widget->event(widget, | ||
1852 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1853 | 2241 | ||
1854 | out: | 2242 | widget->dapm->update = NULL; |
1855 | mutex_unlock(&widget->codec->mutex); | 2243 | } |
1856 | return ret; | 2244 | } |
2245 | |||
2246 | mutex_unlock(&codec->mutex); | ||
2247 | return change; | ||
1857 | } | 2248 | } |
1858 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 2249 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); |
1859 | 2250 | ||
@@ -1892,7 +2283,7 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, | |||
1892 | mutex_lock(&codec->mutex); | 2283 | mutex_lock(&codec->mutex); |
1893 | 2284 | ||
1894 | ucontrol->value.integer.value[0] = | 2285 | ucontrol->value.integer.value[0] = |
1895 | snd_soc_dapm_get_pin_status(codec, pin); | 2286 | snd_soc_dapm_get_pin_status(&codec->dapm, pin); |
1896 | 2287 | ||
1897 | mutex_unlock(&codec->mutex); | 2288 | mutex_unlock(&codec->mutex); |
1898 | 2289 | ||
@@ -1915,11 +2306,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | |||
1915 | mutex_lock(&codec->mutex); | 2306 | mutex_lock(&codec->mutex); |
1916 | 2307 | ||
1917 | if (ucontrol->value.integer.value[0]) | 2308 | if (ucontrol->value.integer.value[0]) |
1918 | snd_soc_dapm_enable_pin(codec, pin); | 2309 | snd_soc_dapm_enable_pin(&codec->dapm, pin); |
1919 | else | 2310 | else |
1920 | snd_soc_dapm_disable_pin(codec, pin); | 2311 | snd_soc_dapm_disable_pin(&codec->dapm, pin); |
1921 | 2312 | ||
1922 | snd_soc_dapm_sync(codec); | 2313 | snd_soc_dapm_sync(&codec->dapm); |
1923 | 2314 | ||
1924 | mutex_unlock(&codec->mutex); | 2315 | mutex_unlock(&codec->mutex); |
1925 | 2316 | ||
@@ -1929,26 +2320,43 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); | |||
1929 | 2320 | ||
1930 | /** | 2321 | /** |
1931 | * snd_soc_dapm_new_control - create new dapm control | 2322 | * snd_soc_dapm_new_control - create new dapm control |
1932 | * @codec: audio codec | 2323 | * @dapm: DAPM context |
1933 | * @widget: widget template | 2324 | * @widget: widget template |
1934 | * | 2325 | * |
1935 | * Creates a new dapm control based upon the template. | 2326 | * Creates a new dapm control based upon the template. |
1936 | * | 2327 | * |
1937 | * Returns 0 for success else error. | 2328 | * Returns 0 for success else error. |
1938 | */ | 2329 | */ |
1939 | int snd_soc_dapm_new_control(struct snd_soc_codec *codec, | 2330 | int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
1940 | const struct snd_soc_dapm_widget *widget) | 2331 | const struct snd_soc_dapm_widget *widget) |
1941 | { | 2332 | { |
1942 | struct snd_soc_dapm_widget *w; | 2333 | struct snd_soc_dapm_widget *w; |
2334 | size_t name_len; | ||
1943 | 2335 | ||
1944 | if ((w = dapm_cnew_widget(widget)) == NULL) | 2336 | if ((w = dapm_cnew_widget(widget)) == NULL) |
1945 | return -ENOMEM; | 2337 | return -ENOMEM; |
1946 | 2338 | ||
1947 | w->codec = codec; | 2339 | name_len = strlen(widget->name) + 1; |
2340 | if (dapm->codec && dapm->codec->name_prefix) | ||
2341 | name_len += 1 + strlen(dapm->codec->name_prefix); | ||
2342 | w->name = kmalloc(name_len, GFP_KERNEL); | ||
2343 | if (w->name == NULL) { | ||
2344 | kfree(w); | ||
2345 | return -ENOMEM; | ||
2346 | } | ||
2347 | if (dapm->codec && dapm->codec->name_prefix) | ||
2348 | snprintf(w->name, name_len, "%s %s", | ||
2349 | dapm->codec->name_prefix, widget->name); | ||
2350 | else | ||
2351 | snprintf(w->name, name_len, "%s", widget->name); | ||
2352 | |||
2353 | dapm->n_widgets++; | ||
2354 | w->dapm = dapm; | ||
2355 | w->codec = dapm->codec; | ||
1948 | INIT_LIST_HEAD(&w->sources); | 2356 | INIT_LIST_HEAD(&w->sources); |
1949 | INIT_LIST_HEAD(&w->sinks); | 2357 | INIT_LIST_HEAD(&w->sinks); |
1950 | INIT_LIST_HEAD(&w->list); | 2358 | INIT_LIST_HEAD(&w->list); |
1951 | list_add(&w->list, &codec->dapm_widgets); | 2359 | list_add(&w->list, &dapm->card->widgets); |
1952 | 2360 | ||
1953 | /* machine layer set ups unconnected pins and insertions */ | 2361 | /* machine layer set ups unconnected pins and insertions */ |
1954 | w->connected = 1; | 2362 | w->connected = 1; |
@@ -1958,7 +2366,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | |||
1958 | 2366 | ||
1959 | /** | 2367 | /** |
1960 | * snd_soc_dapm_new_controls - create new dapm controls | 2368 | * snd_soc_dapm_new_controls - create new dapm controls |
1961 | * @codec: audio codec | 2369 | * @dapm: DAPM context |
1962 | * @widget: widget array | 2370 | * @widget: widget array |
1963 | * @num: number of widgets | 2371 | * @num: number of widgets |
1964 | * | 2372 | * |
@@ -1966,18 +2374,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | |||
1966 | * | 2374 | * |
1967 | * Returns 0 for success else error. | 2375 | * Returns 0 for success else error. |
1968 | */ | 2376 | */ |
1969 | int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, | 2377 | int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, |
1970 | const struct snd_soc_dapm_widget *widget, | 2378 | const struct snd_soc_dapm_widget *widget, |
1971 | int num) | 2379 | int num) |
1972 | { | 2380 | { |
1973 | int i, ret; | 2381 | int i, ret; |
1974 | 2382 | ||
1975 | for (i = 0; i < num; i++) { | 2383 | for (i = 0; i < num; i++) { |
1976 | ret = snd_soc_dapm_new_control(codec, widget); | 2384 | ret = snd_soc_dapm_new_control(dapm, widget); |
1977 | if (ret < 0) { | 2385 | if (ret < 0) { |
1978 | printk(KERN_ERR | 2386 | dev_err(dapm->dev, |
1979 | "ASoC: Failed to create DAPM control %s: %d\n", | 2387 | "ASoC: Failed to create DAPM control %s: %d\n", |
1980 | widget->name, ret); | 2388 | widget->name, ret); |
1981 | return ret; | 2389 | return ret; |
1982 | } | 2390 | } |
1983 | widget++; | 2391 | widget++; |
@@ -1986,33 +2394,17 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, | |||
1986 | } | 2394 | } |
1987 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); | 2395 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); |
1988 | 2396 | ||
1989 | 2397 | static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | |
1990 | /** | 2398 | const char *stream, int event) |
1991 | * snd_soc_dapm_stream_event - send a stream event to the dapm core | ||
1992 | * @codec: audio codec | ||
1993 | * @stream: stream name | ||
1994 | * @event: stream event | ||
1995 | * | ||
1996 | * Sends a stream event to the dapm core. The core then makes any | ||
1997 | * necessary widget power changes. | ||
1998 | * | ||
1999 | * Returns 0 for success else error. | ||
2000 | */ | ||
2001 | int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | ||
2002 | char *stream, int event) | ||
2003 | { | 2399 | { |
2004 | struct snd_soc_dapm_widget *w; | 2400 | struct snd_soc_dapm_widget *w; |
2005 | 2401 | ||
2006 | if (stream == NULL) | 2402 | list_for_each_entry(w, &dapm->card->widgets, list) |
2007 | return 0; | ||
2008 | |||
2009 | mutex_lock(&codec->mutex); | ||
2010 | list_for_each_entry(w, &codec->dapm_widgets, list) | ||
2011 | { | 2403 | { |
2012 | if (!w->sname) | 2404 | if (!w->sname || w->dapm != dapm) |
2013 | continue; | 2405 | continue; |
2014 | pr_debug("widget %s\n %s stream %s event %d\n", | 2406 | dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", |
2015 | w->name, w->sname, stream, event); | 2407 | w->name, w->sname, stream, event); |
2016 | if (strstr(w->sname, stream)) { | 2408 | if (strstr(w->sname, stream)) { |
2017 | switch(event) { | 2409 | switch(event) { |
2018 | case SND_SOC_DAPM_STREAM_START: | 2410 | case SND_SOC_DAPM_STREAM_START: |
@@ -2030,15 +2422,37 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
2030 | } | 2422 | } |
2031 | } | 2423 | } |
2032 | 2424 | ||
2033 | dapm_power_widgets(codec, event); | 2425 | dapm_power_widgets(dapm, event); |
2426 | } | ||
2427 | |||
2428 | /** | ||
2429 | * snd_soc_dapm_stream_event - send a stream event to the dapm core | ||
2430 | * @rtd: PCM runtime data | ||
2431 | * @stream: stream name | ||
2432 | * @event: stream event | ||
2433 | * | ||
2434 | * Sends a stream event to the dapm core. The core then makes any | ||
2435 | * necessary widget power changes. | ||
2436 | * | ||
2437 | * Returns 0 for success else error. | ||
2438 | */ | ||
2439 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, | ||
2440 | const char *stream, int event) | ||
2441 | { | ||
2442 | struct snd_soc_codec *codec = rtd->codec; | ||
2443 | |||
2444 | if (stream == NULL) | ||
2445 | return 0; | ||
2446 | |||
2447 | mutex_lock(&codec->mutex); | ||
2448 | soc_dapm_stream_event(&codec->dapm, stream, event); | ||
2034 | mutex_unlock(&codec->mutex); | 2449 | mutex_unlock(&codec->mutex); |
2035 | return 0; | 2450 | return 0; |
2036 | } | 2451 | } |
2037 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | ||
2038 | 2452 | ||
2039 | /** | 2453 | /** |
2040 | * snd_soc_dapm_enable_pin - enable pin. | 2454 | * snd_soc_dapm_enable_pin - enable pin. |
2041 | * @codec: SoC codec | 2455 | * @dapm: DAPM context |
2042 | * @pin: pin name | 2456 | * @pin: pin name |
2043 | * | 2457 | * |
2044 | * Enables input/output pin and its parents or children widgets iff there is | 2458 | * Enables input/output pin and its parents or children widgets iff there is |
@@ -2046,15 +2460,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | |||
2046 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 2460 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
2047 | * do any widget power switching. | 2461 | * do any widget power switching. |
2048 | */ | 2462 | */ |
2049 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin) | 2463 | int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) |
2050 | { | 2464 | { |
2051 | return snd_soc_dapm_set_pin(codec, pin, 1); | 2465 | return snd_soc_dapm_set_pin(dapm, pin, 1); |
2052 | } | 2466 | } |
2053 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | 2467 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); |
2054 | 2468 | ||
2055 | /** | 2469 | /** |
2056 | * snd_soc_dapm_force_enable_pin - force a pin to be enabled | 2470 | * snd_soc_dapm_force_enable_pin - force a pin to be enabled |
2057 | * @codec: SoC codec | 2471 | * @dapm: DAPM context |
2058 | * @pin: pin name | 2472 | * @pin: pin name |
2059 | * | 2473 | * |
2060 | * Enables input/output pin regardless of any other state. This is | 2474 | * Enables input/output pin regardless of any other state. This is |
@@ -2064,42 +2478,43 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | |||
2064 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 2478 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
2065 | * do any widget power switching. | 2479 | * do any widget power switching. |
2066 | */ | 2480 | */ |
2067 | int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec, const char *pin) | 2481 | int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, |
2482 | const char *pin) | ||
2068 | { | 2483 | { |
2069 | struct snd_soc_dapm_widget *w; | 2484 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); |
2070 | 2485 | ||
2071 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 2486 | if (!w) { |
2072 | if (!strcmp(w->name, pin)) { | 2487 | dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); |
2073 | pr_debug("dapm: %s: pin %s\n", codec->name, pin); | 2488 | return -EINVAL; |
2074 | w->connected = 1; | ||
2075 | w->force = 1; | ||
2076 | return 0; | ||
2077 | } | ||
2078 | } | 2489 | } |
2079 | 2490 | ||
2080 | pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin); | 2491 | dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin); |
2081 | return -EINVAL; | 2492 | w->connected = 1; |
2493 | w->force = 1; | ||
2494 | |||
2495 | return 0; | ||
2082 | } | 2496 | } |
2083 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); | 2497 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); |
2084 | 2498 | ||
2085 | /** | 2499 | /** |
2086 | * snd_soc_dapm_disable_pin - disable pin. | 2500 | * snd_soc_dapm_disable_pin - disable pin. |
2087 | * @codec: SoC codec | 2501 | * @dapm: DAPM context |
2088 | * @pin: pin name | 2502 | * @pin: pin name |
2089 | * | 2503 | * |
2090 | * Disables input/output pin and its parents or children widgets. | 2504 | * Disables input/output pin and its parents or children widgets. |
2091 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 2505 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
2092 | * do any widget power switching. | 2506 | * do any widget power switching. |
2093 | */ | 2507 | */ |
2094 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin) | 2508 | int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, |
2509 | const char *pin) | ||
2095 | { | 2510 | { |
2096 | return snd_soc_dapm_set_pin(codec, pin, 0); | 2511 | return snd_soc_dapm_set_pin(dapm, pin, 0); |
2097 | } | 2512 | } |
2098 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | 2513 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); |
2099 | 2514 | ||
2100 | /** | 2515 | /** |
2101 | * snd_soc_dapm_nc_pin - permanently disable pin. | 2516 | * snd_soc_dapm_nc_pin - permanently disable pin. |
2102 | * @codec: SoC codec | 2517 | * @dapm: DAPM context |
2103 | * @pin: pin name | 2518 | * @pin: pin name |
2104 | * | 2519 | * |
2105 | * Marks the specified pin as being not connected, disabling it along | 2520 | * Marks the specified pin as being not connected, disabling it along |
@@ -2111,29 +2526,28 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | |||
2111 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 2526 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
2112 | * do any widget power switching. | 2527 | * do any widget power switching. |
2113 | */ | 2528 | */ |
2114 | int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin) | 2529 | int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) |
2115 | { | 2530 | { |
2116 | return snd_soc_dapm_set_pin(codec, pin, 0); | 2531 | return snd_soc_dapm_set_pin(dapm, pin, 0); |
2117 | } | 2532 | } |
2118 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); | 2533 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); |
2119 | 2534 | ||
2120 | /** | 2535 | /** |
2121 | * snd_soc_dapm_get_pin_status - get audio pin status | 2536 | * snd_soc_dapm_get_pin_status - get audio pin status |
2122 | * @codec: audio codec | 2537 | * @dapm: DAPM context |
2123 | * @pin: audio signal pin endpoint (or start point) | 2538 | * @pin: audio signal pin endpoint (or start point) |
2124 | * | 2539 | * |
2125 | * Get audio pin status - connected or disconnected. | 2540 | * Get audio pin status - connected or disconnected. |
2126 | * | 2541 | * |
2127 | * Returns 1 for connected otherwise 0. | 2542 | * Returns 1 for connected otherwise 0. |
2128 | */ | 2543 | */ |
2129 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin) | 2544 | int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, |
2545 | const char *pin) | ||
2130 | { | 2546 | { |
2131 | struct snd_soc_dapm_widget *w; | 2547 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); |
2132 | 2548 | ||
2133 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 2549 | if (w) |
2134 | if (!strcmp(w->name, pin)) | 2550 | return w->connected; |
2135 | return w->connected; | ||
2136 | } | ||
2137 | 2551 | ||
2138 | return 0; | 2552 | return 0; |
2139 | } | 2553 | } |
@@ -2141,7 +2555,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); | |||
2141 | 2555 | ||
2142 | /** | 2556 | /** |
2143 | * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint | 2557 | * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint |
2144 | * @codec: audio codec | 2558 | * @dapm: DAPM context |
2145 | * @pin: audio signal pin endpoint (or start point) | 2559 | * @pin: audio signal pin endpoint (or start point) |
2146 | * | 2560 | * |
2147 | * Mark the given endpoint or pin as ignoring suspend. When the | 2561 | * Mark the given endpoint or pin as ignoring suspend. When the |
@@ -2150,50 +2564,48 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); | |||
2150 | * normal means at suspend time, it will not be turned on if it was not | 2564 | * normal means at suspend time, it will not be turned on if it was not |
2151 | * already enabled. | 2565 | * already enabled. |
2152 | */ | 2566 | */ |
2153 | int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin) | 2567 | int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, |
2568 | const char *pin) | ||
2154 | { | 2569 | { |
2155 | struct snd_soc_dapm_widget *w; | 2570 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false); |
2156 | 2571 | ||
2157 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 2572 | if (!w) { |
2158 | if (!strcmp(w->name, pin)) { | 2573 | dev_err(dapm->dev, "dapm: unknown pin %s\n", pin); |
2159 | w->ignore_suspend = 1; | 2574 | return -EINVAL; |
2160 | return 0; | ||
2161 | } | ||
2162 | } | 2575 | } |
2163 | 2576 | ||
2164 | pr_err("Unknown DAPM pin: %s\n", pin); | 2577 | w->ignore_suspend = 1; |
2165 | return -EINVAL; | 2578 | |
2579 | return 0; | ||
2166 | } | 2580 | } |
2167 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); | 2581 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); |
2168 | 2582 | ||
2169 | /** | 2583 | /** |
2170 | * snd_soc_dapm_free - free dapm resources | 2584 | * snd_soc_dapm_free - free dapm resources |
2171 | * @socdev: SoC device | 2585 | * @card: SoC device |
2172 | * | 2586 | * |
2173 | * Free all dapm widgets and resources. | 2587 | * Free all dapm widgets and resources. |
2174 | */ | 2588 | */ |
2175 | void snd_soc_dapm_free(struct snd_soc_device *socdev) | 2589 | void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) |
2176 | { | 2590 | { |
2177 | struct snd_soc_codec *codec = socdev->card->codec; | 2591 | snd_soc_dapm_sys_remove(dapm->dev); |
2178 | 2592 | dapm_debugfs_cleanup(dapm); | |
2179 | snd_soc_dapm_sys_remove(socdev->dev); | 2593 | dapm_free_widgets(dapm); |
2180 | dapm_free_widgets(codec); | 2594 | list_del(&dapm->list); |
2181 | } | 2595 | } |
2182 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | 2596 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
2183 | 2597 | ||
2184 | /* | 2598 | static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) |
2185 | * snd_soc_dapm_shutdown - callback for system shutdown | ||
2186 | */ | ||
2187 | void snd_soc_dapm_shutdown(struct snd_soc_device *socdev) | ||
2188 | { | 2599 | { |
2189 | struct snd_soc_codec *codec = socdev->card->codec; | ||
2190 | struct snd_soc_dapm_widget *w; | 2600 | struct snd_soc_dapm_widget *w; |
2191 | LIST_HEAD(down_list); | 2601 | LIST_HEAD(down_list); |
2192 | int powerdown = 0; | 2602 | int powerdown = 0; |
2193 | 2603 | ||
2194 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 2604 | list_for_each_entry(w, &dapm->card->widgets, list) { |
2605 | if (w->dapm != dapm) | ||
2606 | continue; | ||
2195 | if (w->power) { | 2607 | if (w->power) { |
2196 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 2608 | dapm_seq_insert(w, &down_list, false); |
2197 | w->power = 0; | 2609 | w->power = 0; |
2198 | powerdown = 1; | 2610 | powerdown = 1; |
2199 | } | 2611 | } |
@@ -2203,12 +2615,23 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev) | |||
2203 | * standby. | 2615 | * standby. |
2204 | */ | 2616 | */ |
2205 | if (powerdown) { | 2617 | if (powerdown) { |
2206 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); | 2618 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); |
2207 | dapm_seq_run(codec, &down_list, 0, dapm_down_seq); | 2619 | dapm_seq_run(dapm, &down_list, 0, false); |
2208 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); | 2620 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); |
2209 | } | 2621 | } |
2622 | } | ||
2210 | 2623 | ||
2211 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); | 2624 | /* |
2625 | * snd_soc_dapm_shutdown - callback for system shutdown | ||
2626 | */ | ||
2627 | void snd_soc_dapm_shutdown(struct snd_soc_card *card) | ||
2628 | { | ||
2629 | struct snd_soc_codec *codec; | ||
2630 | |||
2631 | list_for_each_entry(codec, &card->codec_dev_list, list) { | ||
2632 | soc_dapm_shutdown_codec(&codec->dapm); | ||
2633 | snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); | ||
2634 | } | ||
2212 | } | 2635 | } |
2213 | 2636 | ||
2214 | /* Module information */ | 2637 | /* Module information */ |