1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/async.h>
23#include <linux/delay.h>
24#include <linux/pm.h>
25#include <linux/bitops.h>
26#include <linux/platform_device.h>
27#include <linux/jiffies.h>
28#include <linux/debugfs.h>
29#include <linux/pm_runtime.h>
30#include <linux/regulator/consumer.h>
31#include <linux/pinctrl/consumer.h>
32#include <linux/clk.h>
33#include <linux/slab.h>
34#include <sound/core.h>
35#include <sound/pcm.h>
36#include <sound/pcm_params.h>
37#include <sound/soc.h>
38#include <sound/initval.h>
39
40#include <trace/events/asoc.h>
41
42#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
43
44#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
45 SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
46
47#define snd_soc_dapm_for_each_direction(dir) \
48 for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
49 (dir)++)
50
51static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
52 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
53 const char *control,
54 int (*connected)(struct snd_soc_dapm_widget *source,
55 struct snd_soc_dapm_widget *sink));
56
57struct snd_soc_dapm_widget *
58snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
59 const struct snd_soc_dapm_widget *widget);
60
61struct snd_soc_dapm_widget *
62snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
63 const struct snd_soc_dapm_widget *widget);
64
65
66static int dapm_up_seq[] = {
67 [snd_soc_dapm_pre] = 1,
68 [snd_soc_dapm_regulator_supply] = 2,
69 [snd_soc_dapm_pinctrl] = 2,
70 [snd_soc_dapm_clock_supply] = 2,
71 [snd_soc_dapm_supply] = 3,
72 [snd_soc_dapm_micbias] = 4,
73 [snd_soc_dapm_vmid] = 4,
74 [snd_soc_dapm_dai_link] = 3,
75 [snd_soc_dapm_dai_in] = 5,
76 [snd_soc_dapm_dai_out] = 5,
77 [snd_soc_dapm_aif_in] = 5,
78 [snd_soc_dapm_aif_out] = 5,
79 [snd_soc_dapm_mic] = 6,
80 [snd_soc_dapm_siggen] = 6,
81 [snd_soc_dapm_input] = 6,
82 [snd_soc_dapm_output] = 6,
83 [snd_soc_dapm_mux] = 7,
84 [snd_soc_dapm_demux] = 7,
85 [snd_soc_dapm_dac] = 8,
86 [snd_soc_dapm_switch] = 9,
87 [snd_soc_dapm_mixer] = 9,
88 [snd_soc_dapm_mixer_named_ctl] = 9,
89 [snd_soc_dapm_pga] = 10,
90 [snd_soc_dapm_buffer] = 10,
91 [snd_soc_dapm_scheduler] = 10,
92 [snd_soc_dapm_effect] = 10,
93 [snd_soc_dapm_src] = 10,
94 [snd_soc_dapm_asrc] = 10,
95 [snd_soc_dapm_encoder] = 10,
96 [snd_soc_dapm_decoder] = 10,
97 [snd_soc_dapm_adc] = 11,
98 [snd_soc_dapm_out_drv] = 12,
99 [snd_soc_dapm_hp] = 12,
100 [snd_soc_dapm_spk] = 12,
101 [snd_soc_dapm_line] = 12,
102 [snd_soc_dapm_sink] = 12,
103 [snd_soc_dapm_kcontrol] = 13,
104 [snd_soc_dapm_post] = 14,
105};
106
107static int dapm_down_seq[] = {
108 [snd_soc_dapm_pre] = 1,
109 [snd_soc_dapm_kcontrol] = 2,
110 [snd_soc_dapm_adc] = 3,
111 [snd_soc_dapm_hp] = 4,
112 [snd_soc_dapm_spk] = 4,
113 [snd_soc_dapm_line] = 4,
114 [snd_soc_dapm_out_drv] = 4,
115 [snd_soc_dapm_sink] = 4,
116 [snd_soc_dapm_pga] = 5,
117 [snd_soc_dapm_buffer] = 5,
118 [snd_soc_dapm_scheduler] = 5,
119 [snd_soc_dapm_effect] = 5,
120 [snd_soc_dapm_src] = 5,
121 [snd_soc_dapm_asrc] = 5,
122 [snd_soc_dapm_encoder] = 5,
123 [snd_soc_dapm_decoder] = 5,
124 [snd_soc_dapm_switch] = 6,
125 [snd_soc_dapm_mixer_named_ctl] = 6,
126 [snd_soc_dapm_mixer] = 6,
127 [snd_soc_dapm_dac] = 7,
128 [snd_soc_dapm_mic] = 8,
129 [snd_soc_dapm_siggen] = 8,
130 [snd_soc_dapm_input] = 8,
131 [snd_soc_dapm_output] = 8,
132 [snd_soc_dapm_micbias] = 9,
133 [snd_soc_dapm_vmid] = 9,
134 [snd_soc_dapm_mux] = 10,
135 [snd_soc_dapm_demux] = 10,
136 [snd_soc_dapm_aif_in] = 11,
137 [snd_soc_dapm_aif_out] = 11,
138 [snd_soc_dapm_dai_in] = 11,
139 [snd_soc_dapm_dai_out] = 11,
140 [snd_soc_dapm_dai_link] = 12,
141 [snd_soc_dapm_supply] = 13,
142 [snd_soc_dapm_clock_supply] = 14,
143 [snd_soc_dapm_pinctrl] = 14,
144 [snd_soc_dapm_regulator_supply] = 14,
145 [snd_soc_dapm_post] = 15,
146};
147
148static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
149{
150 if (dapm->card && dapm->card->instantiated)
151 lockdep_assert_held(&dapm->card->dapm_mutex);
152}
153
154static void pop_wait(u32 pop_time)
155{
156 if (pop_time)
157 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
158}
159
160__printf(3, 4)
161static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
162{
163 va_list args;
164 char *buf;
165
166 if (!pop_time)
167 return;
168
169 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
170 if (buf == NULL)
171 return;
172
173 va_start(args, fmt);
174 vsnprintf(buf, PAGE_SIZE, fmt, args);
175 dev_info(dev, "%s", buf);
176 va_end(args);
177
178 kfree(buf);
179}
180
181static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
182{
183 return !list_empty(&w->dirty);
184}
185
186static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
187{
188 dapm_assert_locked(w->dapm);
189
190 if (!dapm_dirty_widget(w)) {
191 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
192 w->name, reason);
193 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
194 }
195}
196
197
198
199
200
201
202
203
204static __always_inline void dapm_widget_invalidate_paths(
205 struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir)
206{
207 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
208 struct snd_soc_dapm_widget *node;
209 struct snd_soc_dapm_path *p;
210 LIST_HEAD(list);
211
212 dapm_assert_locked(w->dapm);
213
214 if (w->endpoints[dir] == -1)
215 return;
216
217 list_add_tail(&w->work_list, &list);
218 w->endpoints[dir] = -1;
219
220 list_for_each_entry(w, &list, work_list) {
221 snd_soc_dapm_widget_for_each_path(w, dir, p) {
222 if (p->is_supply || p->weak || !p->connect)
223 continue;
224 node = p->node[rdir];
225 if (node->endpoints[dir] != -1) {
226 node->endpoints[dir] = -1;
227 list_add_tail(&node->work_list, &list);
228 }
229 }
230 }
231}
232
233
234
235
236
237
238
239
240
241
242
243
244
245static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
246{
247 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN);
248}
249
250
251
252
253
254
255
256
257
258
259
260
261
262static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
263{
264 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT);
265}
266
267
268
269
270
271
272
273
274
275
276
277
278static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
279{
280
281
282
283
284 if (p->weak || p->is_supply)
285 return;
286
287
288
289
290
291
292
293 if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0)
294 dapm_widget_invalidate_input_paths(p->sink);
295 if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0)
296 dapm_widget_invalidate_output_paths(p->source);
297}
298
299void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
300{
301 struct snd_soc_dapm_widget *w;
302
303 mutex_lock(&card->dapm_mutex);
304
305 list_for_each_entry(w, &card->widgets, list) {
306 if (w->is_ep) {
307 dapm_mark_dirty(w, "Rechecking endpoints");
308 if (w->is_ep & SND_SOC_DAPM_EP_SINK)
309 dapm_widget_invalidate_output_paths(w);
310 if (w->is_ep & SND_SOC_DAPM_EP_SOURCE)
311 dapm_widget_invalidate_input_paths(w);
312 }
313 }
314
315 mutex_unlock(&card->dapm_mutex);
316}
317EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
318
319
320static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
321 const struct snd_soc_dapm_widget *_widget)
322{
323 struct snd_soc_dapm_widget *w;
324
325 w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
326 if (!w)
327 return NULL;
328
329
330
331
332
333 if (_widget->sname) {
334 w->sname = kstrdup_const(_widget->sname, GFP_KERNEL);
335 if (!w->sname) {
336 kfree(w);
337 return NULL;
338 }
339 }
340 return w;
341}
342
343struct dapm_kcontrol_data {
344 unsigned int value;
345 struct snd_soc_dapm_widget *widget;
346 struct list_head paths;
347 struct snd_soc_dapm_widget_list *wlist;
348};
349
350static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
351 struct snd_kcontrol *kcontrol, const char *ctrl_name)
352{
353 struct dapm_kcontrol_data *data;
354 struct soc_mixer_control *mc;
355 struct soc_enum *e;
356 const char *name;
357 int ret;
358
359 data = kzalloc(sizeof(*data), GFP_KERNEL);
360 if (!data)
361 return -ENOMEM;
362
363 INIT_LIST_HEAD(&data->paths);
364
365 switch (widget->id) {
366 case snd_soc_dapm_switch:
367 case snd_soc_dapm_mixer:
368 case snd_soc_dapm_mixer_named_ctl:
369 mc = (struct soc_mixer_control *)kcontrol->private_value;
370
371 if (mc->autodisable && snd_soc_volsw_is_stereo(mc))
372 dev_warn(widget->dapm->dev,
373 "ASoC: Unsupported stereo autodisable control '%s'\n",
374 ctrl_name);
375
376 if (mc->autodisable) {
377 struct snd_soc_dapm_widget template;
378
379 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
380 "Autodisable");
381 if (!name) {
382 ret = -ENOMEM;
383 goto err_data;
384 }
385
386 memset(&template, 0, sizeof(template));
387 template.reg = mc->reg;
388 template.mask = (1 << fls(mc->max)) - 1;
389 template.shift = mc->shift;
390 if (mc->invert)
391 template.off_val = mc->max;
392 else
393 template.off_val = 0;
394 template.on_val = template.off_val;
395 template.id = snd_soc_dapm_kcontrol;
396 template.name = name;
397
398 data->value = template.on_val;
399
400 data->widget =
401 snd_soc_dapm_new_control_unlocked(widget->dapm,
402 &template);
403 kfree(name);
404 if (IS_ERR(data->widget)) {
405 ret = PTR_ERR(data->widget);
406 goto err_data;
407 }
408 }
409 break;
410 case snd_soc_dapm_demux:
411 case snd_soc_dapm_mux:
412 e = (struct soc_enum *)kcontrol->private_value;
413
414 if (e->autodisable) {
415 struct snd_soc_dapm_widget template;
416
417 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
418 "Autodisable");
419 if (!name) {
420 ret = -ENOMEM;
421 goto err_data;
422 }
423
424 memset(&template, 0, sizeof(template));
425 template.reg = e->reg;
426 template.mask = e->mask << e->shift_l;
427 template.shift = e->shift_l;
428 template.off_val = snd_soc_enum_item_to_val(e, 0);
429 template.on_val = template.off_val;
430 template.id = snd_soc_dapm_kcontrol;
431 template.name = name;
432
433 data->value = template.on_val;
434
435 data->widget = snd_soc_dapm_new_control_unlocked(
436 widget->dapm, &template);
437 kfree(name);
438 if (IS_ERR(data->widget)) {
439 ret = PTR_ERR(data->widget);
440 goto err_data;
441 }
442
443 snd_soc_dapm_add_path(widget->dapm, data->widget,
444 widget, NULL, NULL);
445 }
446 break;
447 default:
448 break;
449 }
450
451 kcontrol->private_data = data;
452
453 return 0;
454
455err_data:
456 kfree(data);
457 return ret;
458}
459
460static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
461{
462 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
463
464 list_del(&data->paths);
465 kfree(data->wlist);
466 kfree(data);
467}
468
469static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
470 const struct snd_kcontrol *kcontrol)
471{
472 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
473
474 return data->wlist;
475}
476
477static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
478 struct snd_soc_dapm_widget *widget)
479{
480 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
481 struct snd_soc_dapm_widget_list *new_wlist;
482 unsigned int n;
483
484 if (data->wlist)
485 n = data->wlist->num_widgets + 1;
486 else
487 n = 1;
488
489 new_wlist = krealloc(data->wlist,
490 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
491 if (!new_wlist)
492 return -ENOMEM;
493
494 new_wlist->widgets[n - 1] = widget;
495 new_wlist->num_widgets = n;
496
497 data->wlist = new_wlist;
498
499 return 0;
500}
501
502static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
503 struct snd_soc_dapm_path *path)
504{
505 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
506
507 list_add_tail(&path->list_kcontrol, &data->paths);
508}
509
510static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
511{
512 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
513
514 if (!data->widget)
515 return true;
516
517 return data->widget->power;
518}
519
520static struct list_head *dapm_kcontrol_get_path_list(
521 const struct snd_kcontrol *kcontrol)
522{
523 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
524
525 return &data->paths;
526}
527
528#define dapm_kcontrol_for_each_path(path, kcontrol) \
529 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
530 list_kcontrol)
531
532unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
533{
534 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
535
536 return data->value;
537}
538EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
539
540static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
541 unsigned int value)
542{
543 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
544
545 if (data->value == value)
546 return false;
547
548 if (data->widget)
549 data->widget->on_val = value;
550
551 data->value = value;
552
553 return true;
554}
555
556
557
558
559
560
561struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
562 struct snd_kcontrol *kcontrol)
563{
564 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
565}
566EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
567
568
569
570
571
572
573
574
575
576struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
577 struct snd_kcontrol *kcontrol)
578{
579 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
580}
581EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
582
583static void dapm_reset(struct snd_soc_card *card)
584{
585 struct snd_soc_dapm_widget *w;
586
587 lockdep_assert_held(&card->dapm_mutex);
588
589 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
590
591 list_for_each_entry(w, &card->widgets, list) {
592 w->new_power = w->power;
593 w->power_checked = false;
594 }
595}
596
597static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
598{
599 if (!dapm->component)
600 return NULL;
601 return dapm->component->name_prefix;
602}
603
604static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
605 unsigned int *value)
606{
607 if (!dapm->component)
608 return -EIO;
609 return snd_soc_component_read(dapm->component, reg, value);
610}
611
612static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
613 int reg, unsigned int mask, unsigned int value)
614{
615 if (!dapm->component)
616 return -EIO;
617 return snd_soc_component_update_bits(dapm->component, reg,
618 mask, value);
619}
620
621static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
622 int reg, unsigned int mask, unsigned int value)
623{
624 if (!dapm->component)
625 return -EIO;
626 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
627}
628
629static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
630{
631 if (dapm->component)
632 snd_soc_component_async_complete(dapm->component);
633}
634
635static struct snd_soc_dapm_widget *
636dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
637{
638 struct snd_soc_dapm_widget *w = wcache->widget;
639 struct list_head *wlist;
640 const int depth = 2;
641 int i = 0;
642
643 if (w) {
644 wlist = &w->dapm->card->widgets;
645
646 list_for_each_entry_from(w, wlist, list) {
647 if (!strcmp(name, w->name))
648 return w;
649
650 if (++i == depth)
651 break;
652 }
653 }
654
655 return NULL;
656}
657
658static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
659 struct snd_soc_dapm_widget *w)
660{
661 wcache->widget = w;
662}
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
682 enum snd_soc_bias_level level)
683{
684 int ret = 0;
685
686 if (dapm->set_bias_level)
687 ret = dapm->set_bias_level(dapm, level);
688
689 if (ret == 0)
690 dapm->bias_level = level;
691
692 return ret;
693}
694EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
695
696
697
698
699
700
701
702
703
704
705static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
706 enum snd_soc_bias_level level)
707{
708 struct snd_soc_card *card = dapm->card;
709 int ret = 0;
710
711 trace_snd_soc_bias_level_start(card, level);
712
713 if (card && card->set_bias_level)
714 ret = card->set_bias_level(card, dapm, level);
715 if (ret != 0)
716 goto out;
717
718 if (!card || dapm != &card->dapm)
719 ret = snd_soc_dapm_force_bias_level(dapm, level);
720
721 if (ret != 0)
722 goto out;
723
724 if (card && card->set_bias_level_post)
725 ret = card->set_bias_level_post(card, dapm, level);
726out:
727 trace_snd_soc_bias_level_done(card, level);
728
729 return ret;
730}
731
732
733static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
734 struct snd_soc_dapm_path *path, const char *control_name,
735 struct snd_soc_dapm_widget *w)
736{
737 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
738 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
739 unsigned int val, item;
740 int i;
741
742 if (e->reg != SND_SOC_NOPM) {
743 soc_dapm_read(dapm, e->reg, &val);
744 val = (val >> e->shift_l) & e->mask;
745 item = snd_soc_enum_val_to_item(e, val);
746 } else {
747
748
749
750
751
752
753 item = 0;
754 }
755
756 i = match_string(e->texts, e->items, control_name);
757 if (i < 0)
758 return -ENODEV;
759
760 path->name = e->texts[i];
761 path->connect = (i == item);
762 return 0;
763
764}
765
766
767static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
768 int nth_path)
769{
770 struct soc_mixer_control *mc = (struct soc_mixer_control *)
771 p->sink->kcontrol_news[i].private_value;
772 unsigned int reg = mc->reg;
773 unsigned int shift = mc->shift;
774 unsigned int max = mc->max;
775 unsigned int mask = (1 << fls(max)) - 1;
776 unsigned int invert = mc->invert;
777 unsigned int val;
778
779 if (reg != SND_SOC_NOPM) {
780 soc_dapm_read(p->sink->dapm, reg, &val);
781
782
783
784
785
786
787
788
789
790
791
792
793 if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
794 if (reg != mc->rreg)
795 soc_dapm_read(p->sink->dapm, mc->rreg, &val);
796 val = (val >> mc->rshift) & mask;
797 } else {
798 val = (val >> shift) & mask;
799 }
800 if (invert)
801 val = max - val;
802 p->connect = !!val;
803 } else {
804 p->connect = 0;
805 }
806}
807
808
809static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
810 struct snd_soc_dapm_path *path, const char *control_name)
811{
812 int i, nth_path = 0;
813
814
815 for (i = 0; i < path->sink->num_kcontrols; i++) {
816 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
817 path->name = path->sink->kcontrol_news[i].name;
818 dapm_set_mixer_path_status(path, i, nth_path++);
819 return 0;
820 }
821 }
822 return -ENODEV;
823}
824
825static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
826 struct snd_soc_dapm_widget *kcontrolw,
827 const struct snd_kcontrol_new *kcontrol_new,
828 struct snd_kcontrol **kcontrol)
829{
830 struct snd_soc_dapm_widget *w;
831 int i;
832
833 *kcontrol = NULL;
834
835 list_for_each_entry(w, &dapm->card->widgets, list) {
836 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
837 continue;
838 for (i = 0; i < w->num_kcontrols; i++) {
839 if (&w->kcontrol_news[i] == kcontrol_new) {
840 if (w->kcontrols)
841 *kcontrol = w->kcontrols[i];
842 return 1;
843 }
844 }
845 }
846
847 return 0;
848}
849
850
851
852
853
854static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
855 int kci)
856{
857 struct snd_soc_dapm_context *dapm = w->dapm;
858 struct snd_card *card = dapm->card->snd_card;
859 const char *prefix;
860 size_t prefix_len;
861 int shared;
862 struct snd_kcontrol *kcontrol;
863 bool wname_in_long_name, kcname_in_long_name;
864 char *long_name = NULL;
865 const char *name;
866 int ret = 0;
867
868 prefix = soc_dapm_prefix(dapm);
869 if (prefix)
870 prefix_len = strlen(prefix) + 1;
871 else
872 prefix_len = 0;
873
874 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
875 &kcontrol);
876
877 if (!kcontrol) {
878 if (shared) {
879 wname_in_long_name = false;
880 kcname_in_long_name = true;
881 } else {
882 switch (w->id) {
883 case snd_soc_dapm_switch:
884 case snd_soc_dapm_mixer:
885 case snd_soc_dapm_pga:
886 case snd_soc_dapm_effect:
887 case snd_soc_dapm_out_drv:
888 wname_in_long_name = true;
889 kcname_in_long_name = true;
890 break;
891 case snd_soc_dapm_mixer_named_ctl:
892 wname_in_long_name = false;
893 kcname_in_long_name = true;
894 break;
895 case snd_soc_dapm_demux:
896 case snd_soc_dapm_mux:
897 wname_in_long_name = true;
898 kcname_in_long_name = false;
899 break;
900 default:
901 return -EINVAL;
902 }
903 }
904
905 if (wname_in_long_name && kcname_in_long_name) {
906
907
908
909
910
911
912 long_name = kasprintf(GFP_KERNEL, "%s %s",
913 w->name + prefix_len,
914 w->kcontrol_news[kci].name);
915 if (long_name == NULL)
916 return -ENOMEM;
917
918 name = long_name;
919 } else if (wname_in_long_name) {
920 long_name = NULL;
921 name = w->name + prefix_len;
922 } else {
923 long_name = NULL;
924 name = w->kcontrol_news[kci].name;
925 }
926
927 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
928 prefix);
929 if (!kcontrol) {
930 ret = -ENOMEM;
931 goto exit_free;
932 }
933
934 kcontrol->private_free = dapm_kcontrol_free;
935
936 ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
937 if (ret) {
938 snd_ctl_free_one(kcontrol);
939 goto exit_free;
940 }
941
942 ret = snd_ctl_add(card, kcontrol);
943 if (ret < 0) {
944 dev_err(dapm->dev,
945 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
946 w->name, name, ret);
947 goto exit_free;
948 }
949 }
950
951 ret = dapm_kcontrol_add_widget(kcontrol, w);
952 if (ret == 0)
953 w->kcontrols[kci] = kcontrol;
954
955exit_free:
956 kfree(long_name);
957
958 return ret;
959}
960
961
962static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
963{
964 int i, ret;
965 struct snd_soc_dapm_path *path;
966 struct dapm_kcontrol_data *data;
967
968
969 for (i = 0; i < w->num_kcontrols; i++) {
970
971 snd_soc_dapm_widget_for_each_source_path(w, path) {
972
973 if (path->name != (char *)w->kcontrol_news[i].name)
974 continue;
975
976 if (!w->kcontrols[i]) {
977 ret = dapm_create_or_share_kcontrol(w, i);
978 if (ret < 0)
979 return ret;
980 }
981
982 dapm_kcontrol_add_path(w->kcontrols[i], path);
983
984 data = snd_kcontrol_chip(w->kcontrols[i]);
985 if (data->widget)
986 snd_soc_dapm_add_path(data->widget->dapm,
987 data->widget,
988 path->source,
989 NULL, NULL);
990 }
991 }
992
993 return 0;
994}
995
996
997static int dapm_new_mux(struct snd_soc_dapm_widget *w)
998{
999 struct snd_soc_dapm_context *dapm = w->dapm;
1000 enum snd_soc_dapm_direction dir;
1001 struct snd_soc_dapm_path *path;
1002 const char *type;
1003 int ret;
1004
1005 switch (w->id) {
1006 case snd_soc_dapm_mux:
1007 dir = SND_SOC_DAPM_DIR_OUT;
1008 type = "mux";
1009 break;
1010 case snd_soc_dapm_demux:
1011 dir = SND_SOC_DAPM_DIR_IN;
1012 type = "demux";
1013 break;
1014 default:
1015 return -EINVAL;
1016 }
1017
1018 if (w->num_kcontrols != 1) {
1019 dev_err(dapm->dev,
1020 "ASoC: %s %s has incorrect number of controls\n", type,
1021 w->name);
1022 return -EINVAL;
1023 }
1024
1025 if (list_empty(&w->edges[dir])) {
1026 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
1027 return -EINVAL;
1028 }
1029
1030 ret = dapm_create_or_share_kcontrol(w, 0);
1031 if (ret < 0)
1032 return ret;
1033
1034 snd_soc_dapm_widget_for_each_path(w, dir, path) {
1035 if (path->name)
1036 dapm_kcontrol_add_path(w->kcontrols[0], path);
1037 }
1038
1039 return 0;
1040}
1041
1042
1043static int dapm_new_pga(struct snd_soc_dapm_widget *w)
1044{
1045 int i, ret;
1046
1047 for (i = 0; i < w->num_kcontrols; i++) {
1048 ret = dapm_create_or_share_kcontrol(w, i);
1049 if (ret < 0)
1050 return ret;
1051 }
1052
1053 return 0;
1054}
1055
1056
1057static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
1058{
1059 int i, ret;
1060 struct snd_kcontrol *kcontrol;
1061 struct snd_soc_dapm_context *dapm = w->dapm;
1062 struct snd_card *card = dapm->card->snd_card;
1063 struct snd_soc_pcm_runtime *rtd = w->priv;
1064
1065
1066 if (rtd->dai_link->num_params <= 1)
1067 return 0;
1068
1069
1070 for (i = 0; i < w->num_kcontrols; i++) {
1071 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
1072 w->name, NULL);
1073 ret = snd_ctl_add(card, kcontrol);
1074 if (ret < 0) {
1075 dev_err(dapm->dev,
1076 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1077 w->name, w->kcontrol_news[i].name, ret);
1078 return ret;
1079 }
1080 kcontrol->private_data = w;
1081 w->kcontrols[i] = kcontrol;
1082 }
1083
1084 return 0;
1085}
1086
1087
1088
1089
1090
1091static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1092{
1093 int level = snd_power_get_state(widget->dapm->card->snd_card);
1094
1095 switch (level) {
1096 case SNDRV_CTL_POWER_D3hot:
1097 case SNDRV_CTL_POWER_D3cold:
1098 if (widget->ignore_suspend)
1099 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
1100 widget->name);
1101 return widget->ignore_suspend;
1102 default:
1103 return 1;
1104 }
1105}
1106
1107static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1108 struct list_head *widgets)
1109{
1110 struct snd_soc_dapm_widget *w;
1111 struct list_head *it;
1112 unsigned int size = 0;
1113 unsigned int i = 0;
1114
1115 list_for_each(it, widgets)
1116 size++;
1117
1118 *list = kzalloc(struct_size(*list, widgets, size), GFP_KERNEL);
1119 if (*list == NULL)
1120 return -ENOMEM;
1121
1122 list_for_each_entry(w, widgets, work_list)
1123 (*list)->widgets[i++] = w;
1124
1125 (*list)->num_widgets = i;
1126
1127 return 0;
1128}
1129
1130
1131
1132
1133
1134
1135
1136
1137static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
1138 struct list_head *list, enum snd_soc_dapm_direction dir,
1139 int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
1140 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1141 enum snd_soc_dapm_direction)),
1142 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1143 enum snd_soc_dapm_direction))
1144{
1145 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
1146 struct snd_soc_dapm_path *path;
1147 int con = 0;
1148
1149 if (widget->endpoints[dir] >= 0)
1150 return widget->endpoints[dir];
1151
1152 DAPM_UPDATE_STAT(widget, path_checks);
1153
1154
1155 if (list)
1156 list_add_tail(&widget->work_list, list);
1157
1158 if (custom_stop_condition && custom_stop_condition(widget, dir)) {
1159 widget->endpoints[dir] = 1;
1160 return widget->endpoints[dir];
1161 }
1162
1163 if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
1164 widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
1165 return widget->endpoints[dir];
1166 }
1167
1168 snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
1169 DAPM_UPDATE_STAT(widget, neighbour_checks);
1170
1171 if (path->weak || path->is_supply)
1172 continue;
1173
1174 if (path->walking)
1175 return 1;
1176
1177 trace_snd_soc_dapm_path(widget, dir, path);
1178
1179 if (path->connect) {
1180 path->walking = 1;
1181 con += fn(path->node[dir], list, custom_stop_condition);
1182 path->walking = 0;
1183 }
1184 }
1185
1186 widget->endpoints[dir] = con;
1187
1188 return con;
1189}
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
1201 struct list_head *list,
1202 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1203 enum snd_soc_dapm_direction))
1204{
1205 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
1206 is_connected_output_ep, custom_stop_condition);
1207}
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
1219 struct list_head *list,
1220 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1221 enum snd_soc_dapm_direction))
1222{
1223 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
1224 is_connected_input_ep, custom_stop_condition);
1225}
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1247 struct snd_soc_dapm_widget_list **list,
1248 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1249 enum snd_soc_dapm_direction))
1250{
1251 struct snd_soc_card *card = dai->component->card;
1252 struct snd_soc_dapm_widget *w;
1253 LIST_HEAD(widgets);
1254 int paths;
1255 int ret;
1256
1257 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
1258
1259
1260
1261
1262
1263 list_for_each_entry(w, &card->widgets, list) {
1264 w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
1265 w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
1266 }
1267
1268 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1269 paths = is_connected_output_ep(dai->playback_widget, &widgets,
1270 custom_stop_condition);
1271 else
1272 paths = is_connected_input_ep(dai->capture_widget, &widgets,
1273 custom_stop_condition);
1274
1275
1276 list_del(widgets.next);
1277
1278 ret = dapm_widget_list_create(list, &widgets);
1279 if (ret)
1280 paths = ret;
1281
1282 trace_snd_soc_dapm_connected(paths, stream);
1283 mutex_unlock(&card->dapm_mutex);
1284
1285 return paths;
1286}
1287
1288
1289
1290
1291int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1292 struct snd_kcontrol *kcontrol, int event)
1293{
1294 int ret;
1295
1296 soc_dapm_async_complete(w->dapm);
1297
1298 if (SND_SOC_DAPM_EVENT_ON(event)) {
1299 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
1300 ret = regulator_allow_bypass(w->regulator, false);
1301 if (ret != 0)
1302 dev_warn(w->dapm->dev,
1303 "ASoC: Failed to unbypass %s: %d\n",
1304 w->name, ret);
1305 }
1306
1307 return regulator_enable(w->regulator);
1308 } else {
1309 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
1310 ret = regulator_allow_bypass(w->regulator, true);
1311 if (ret != 0)
1312 dev_warn(w->dapm->dev,
1313 "ASoC: Failed to bypass %s: %d\n",
1314 w->name, ret);
1315 }
1316
1317 return regulator_disable_deferred(w->regulator, w->shift);
1318 }
1319}
1320EXPORT_SYMBOL_GPL(dapm_regulator_event);
1321
1322
1323
1324
1325int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
1326 struct snd_kcontrol *kcontrol, int event)
1327{
1328 struct snd_soc_dapm_pinctrl_priv *priv = w->priv;
1329 struct pinctrl *p = w->pinctrl;
1330 struct pinctrl_state *s;
1331
1332 if (!p || !priv)
1333 return -EIO;
1334
1335 if (SND_SOC_DAPM_EVENT_ON(event))
1336 s = pinctrl_lookup_state(p, priv->active_state);
1337 else
1338 s = pinctrl_lookup_state(p, priv->sleep_state);
1339
1340 if (IS_ERR(s))
1341 return PTR_ERR(s);
1342
1343 return pinctrl_select_state(p, s);
1344}
1345EXPORT_SYMBOL_GPL(dapm_pinctrl_event);
1346
1347
1348
1349
1350int dapm_clock_event(struct snd_soc_dapm_widget *w,
1351 struct snd_kcontrol *kcontrol, int event)
1352{
1353 if (!w->clk)
1354 return -EIO;
1355
1356 soc_dapm_async_complete(w->dapm);
1357
1358 if (SND_SOC_DAPM_EVENT_ON(event)) {
1359 return clk_prepare_enable(w->clk);
1360 } else {
1361 clk_disable_unprepare(w->clk);
1362 return 0;
1363 }
1364
1365 return 0;
1366}
1367EXPORT_SYMBOL_GPL(dapm_clock_event);
1368
1369static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1370{
1371 if (w->power_checked)
1372 return w->new_power;
1373
1374 if (w->force)
1375 w->new_power = 1;
1376 else
1377 w->new_power = w->power_check(w);
1378
1379 w->power_checked = true;
1380
1381 return w->new_power;
1382}
1383
1384
1385static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1386{
1387 int in, out;
1388
1389 DAPM_UPDATE_STAT(w, power_checks);
1390
1391 in = is_connected_input_ep(w, NULL, NULL);
1392 out = is_connected_output_ep(w, NULL, NULL);
1393 return out != 0 && in != 0;
1394}
1395
1396
1397static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1398{
1399 struct snd_soc_dapm_path *path;
1400
1401 DAPM_UPDATE_STAT(w, power_checks);
1402
1403
1404 snd_soc_dapm_widget_for_each_sink_path(w, path) {
1405 DAPM_UPDATE_STAT(w, neighbour_checks);
1406
1407 if (path->weak)
1408 continue;
1409
1410 if (path->connected &&
1411 !path->connected(path->source, path->sink))
1412 continue;
1413
1414 if (dapm_widget_power_check(path->sink))
1415 return 1;
1416 }
1417
1418 return 0;
1419}
1420
1421static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1422{
1423 return w->connected;
1424}
1425
1426static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1427 struct snd_soc_dapm_widget *b,
1428 bool power_up)
1429{
1430 int *sort;
1431
1432 BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT);
1433 BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT);
1434
1435 if (power_up)
1436 sort = dapm_up_seq;
1437 else
1438 sort = dapm_down_seq;
1439
1440 WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id);
1441 WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id);
1442
1443 if (sort[a->id] != sort[b->id])
1444 return sort[a->id] - sort[b->id];
1445 if (a->subseq != b->subseq) {
1446 if (power_up)
1447 return a->subseq - b->subseq;
1448 else
1449 return b->subseq - a->subseq;
1450 }
1451 if (a->reg != b->reg)
1452 return a->reg - b->reg;
1453 if (a->dapm != b->dapm)
1454 return (unsigned long)a->dapm - (unsigned long)b->dapm;
1455
1456 return 0;
1457}
1458
1459
1460static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1461 struct list_head *list,
1462 bool power_up)
1463{
1464 struct snd_soc_dapm_widget *w;
1465
1466 list_for_each_entry(w, list, power_list)
1467 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
1468 list_add_tail(&new_widget->power_list, &w->power_list);
1469 return;
1470 }
1471
1472 list_add_tail(&new_widget->power_list, list);
1473}
1474
1475static void dapm_seq_check_event(struct snd_soc_card *card,
1476 struct snd_soc_dapm_widget *w, int event)
1477{
1478 const char *ev_name;
1479 int power, ret;
1480
1481 switch (event) {
1482 case SND_SOC_DAPM_PRE_PMU:
1483 ev_name = "PRE_PMU";
1484 power = 1;
1485 break;
1486 case SND_SOC_DAPM_POST_PMU:
1487 ev_name = "POST_PMU";
1488 power = 1;
1489 break;
1490 case SND_SOC_DAPM_PRE_PMD:
1491 ev_name = "PRE_PMD";
1492 power = 0;
1493 break;
1494 case SND_SOC_DAPM_POST_PMD:
1495 ev_name = "POST_PMD";
1496 power = 0;
1497 break;
1498 case SND_SOC_DAPM_WILL_PMU:
1499 ev_name = "WILL_PMU";
1500 power = 1;
1501 break;
1502 case SND_SOC_DAPM_WILL_PMD:
1503 ev_name = "WILL_PMD";
1504 power = 0;
1505 break;
1506 default:
1507 WARN(1, "Unknown event %d\n", event);
1508 return;
1509 }
1510
1511 if (w->new_power != power)
1512 return;
1513
1514 if (w->event && (w->event_flags & event)) {
1515 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
1516 w->name, ev_name);
1517 soc_dapm_async_complete(w->dapm);
1518 trace_snd_soc_dapm_widget_event_start(w, event);
1519 ret = w->event(w, NULL, event);
1520 trace_snd_soc_dapm_widget_event_done(w, event);
1521 if (ret < 0)
1522 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
1523 ev_name, w->name, ret);
1524 }
1525}
1526
1527
1528static void dapm_seq_run_coalesced(struct snd_soc_card *card,
1529 struct list_head *pending)
1530{
1531 struct snd_soc_dapm_context *dapm;
1532 struct snd_soc_dapm_widget *w;
1533 int reg;
1534 unsigned int value = 0;
1535 unsigned int mask = 0;
1536
1537 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1538 reg = w->reg;
1539 dapm = w->dapm;
1540
1541 list_for_each_entry(w, pending, power_list) {
1542 WARN_ON(reg != w->reg || dapm != w->dapm);
1543 w->power = w->new_power;
1544
1545 mask |= w->mask << w->shift;
1546 if (w->power)
1547 value |= w->on_val << w->shift;
1548 else
1549 value |= w->off_val << w->shift;
1550
1551 pop_dbg(dapm->dev, card->pop_time,
1552 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1553 w->name, reg, value, mask);
1554
1555
1556 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1557 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
1558 }
1559
1560 if (reg >= 0) {
1561
1562
1563
1564
1565 pop_dbg(dapm->dev, card->pop_time,
1566 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
1567 value, mask, reg, card->pop_time);
1568 pop_wait(card->pop_time);
1569 soc_dapm_update_bits(dapm, reg, mask, value);
1570 }
1571
1572 list_for_each_entry(w, pending, power_list) {
1573 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1574 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
1575 }
1576}
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586static void dapm_seq_run(struct snd_soc_card *card,
1587 struct list_head *list, int event, bool power_up)
1588{
1589 struct snd_soc_dapm_widget *w, *n;
1590 struct snd_soc_dapm_context *d;
1591 LIST_HEAD(pending);
1592 int cur_sort = -1;
1593 int cur_subseq = -1;
1594 int cur_reg = SND_SOC_NOPM;
1595 struct snd_soc_dapm_context *cur_dapm = NULL;
1596 int ret, i;
1597 int *sort;
1598
1599 if (power_up)
1600 sort = dapm_up_seq;
1601 else
1602 sort = dapm_down_seq;
1603
1604 list_for_each_entry_safe(w, n, list, power_list) {
1605 ret = 0;
1606
1607
1608 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
1609 w->dapm != cur_dapm || w->subseq != cur_subseq) {
1610 if (!list_empty(&pending))
1611 dapm_seq_run_coalesced(card, &pending);
1612
1613 if (cur_dapm && cur_dapm->seq_notifier) {
1614 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1615 if (sort[i] == cur_sort)
1616 cur_dapm->seq_notifier(cur_dapm,
1617 i,
1618 cur_subseq);
1619 }
1620
1621 if (cur_dapm && w->dapm != cur_dapm)
1622 soc_dapm_async_complete(cur_dapm);
1623
1624 INIT_LIST_HEAD(&pending);
1625 cur_sort = -1;
1626 cur_subseq = INT_MIN;
1627 cur_reg = SND_SOC_NOPM;
1628 cur_dapm = NULL;
1629 }
1630
1631 switch (w->id) {
1632 case snd_soc_dapm_pre:
1633 if (!w->event)
1634 list_for_each_entry_safe_continue(w, n, list,
1635 power_list);
1636
1637 if (event == SND_SOC_DAPM_STREAM_START)
1638 ret = w->event(w,
1639 NULL, SND_SOC_DAPM_PRE_PMU);
1640 else if (event == SND_SOC_DAPM_STREAM_STOP)
1641 ret = w->event(w,
1642 NULL, SND_SOC_DAPM_PRE_PMD);
1643 break;
1644
1645 case snd_soc_dapm_post:
1646 if (!w->event)
1647 list_for_each_entry_safe_continue(w, n, list,
1648 power_list);
1649
1650 if (event == SND_SOC_DAPM_STREAM_START)
1651 ret = w->event(w,
1652 NULL, SND_SOC_DAPM_POST_PMU);
1653 else if (event == SND_SOC_DAPM_STREAM_STOP)
1654 ret = w->event(w,
1655 NULL, SND_SOC_DAPM_POST_PMD);
1656 break;
1657
1658 default:
1659
1660 cur_sort = sort[w->id];
1661 cur_subseq = w->subseq;
1662 cur_reg = w->reg;
1663 cur_dapm = w->dapm;
1664 list_move(&w->power_list, &pending);
1665 break;
1666 }
1667
1668 if (ret < 0)
1669 dev_err(w->dapm->dev,
1670 "ASoC: Failed to apply widget power: %d\n", ret);
1671 }
1672
1673 if (!list_empty(&pending))
1674 dapm_seq_run_coalesced(card, &pending);
1675
1676 if (cur_dapm && cur_dapm->seq_notifier) {
1677 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1678 if (sort[i] == cur_sort)
1679 cur_dapm->seq_notifier(cur_dapm,
1680 i, cur_subseq);
1681 }
1682
1683 list_for_each_entry(d, &card->dapm_list, list) {
1684 soc_dapm_async_complete(d);
1685 }
1686}
1687
1688static void dapm_widget_update(struct snd_soc_card *card)
1689{
1690 struct snd_soc_dapm_update *update = card->update;
1691 struct snd_soc_dapm_widget_list *wlist;
1692 struct snd_soc_dapm_widget *w = NULL;
1693 unsigned int wi;
1694 int ret;
1695
1696 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
1697 return;
1698
1699 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
1700
1701 for (wi = 0; wi < wlist->num_widgets; wi++) {
1702 w = wlist->widgets[wi];
1703
1704 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1705 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1706 if (ret != 0)
1707 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
1708 w->name, ret);
1709 }
1710 }
1711
1712 if (!w)
1713 return;
1714
1715 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1716 update->val);
1717 if (ret < 0)
1718 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
1719 w->name, ret);
1720
1721 if (update->has_second_set) {
1722 ret = soc_dapm_update_bits(w->dapm, update->reg2,
1723 update->mask2, update->val2);
1724 if (ret < 0)
1725 dev_err(w->dapm->dev,
1726 "ASoC: %s DAPM update failed: %d\n",
1727 w->name, ret);
1728 }
1729
1730 for (wi = 0; wi < wlist->num_widgets; wi++) {
1731 w = wlist->widgets[wi];
1732
1733 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1734 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1735 if (ret != 0)
1736 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
1737 w->name, ret);
1738 }
1739 }
1740}
1741
1742
1743
1744
1745static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1746{
1747 struct snd_soc_dapm_context *d = data;
1748 int ret;
1749
1750
1751 if (d->bias_level == SND_SOC_BIAS_OFF &&
1752 d->target_bias_level != SND_SOC_BIAS_OFF) {
1753 if (d->dev)
1754 pm_runtime_get_sync(d->dev);
1755
1756 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1757 if (ret != 0)
1758 dev_err(d->dev,
1759 "ASoC: Failed to turn on bias: %d\n", ret);
1760 }
1761
1762
1763 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1764 d->bias_level != SND_SOC_BIAS_ON) ||
1765 (d->target_bias_level != SND_SOC_BIAS_ON &&
1766 d->bias_level == SND_SOC_BIAS_ON)) {
1767 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1768 if (ret != 0)
1769 dev_err(d->dev,
1770 "ASoC: Failed to prepare bias: %d\n", ret);
1771 }
1772}
1773
1774
1775
1776
1777static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1778{
1779 struct snd_soc_dapm_context *d = data;
1780 int ret;
1781
1782
1783 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1784 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1785 d->target_bias_level == SND_SOC_BIAS_OFF)) {
1786 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1787 if (ret != 0)
1788 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
1789 ret);
1790 }
1791
1792
1793 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1794 d->target_bias_level == SND_SOC_BIAS_OFF) {
1795 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1796 if (ret != 0)
1797 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1798 ret);
1799
1800 if (d->dev)
1801 pm_runtime_put(d->dev);
1802 }
1803
1804
1805 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1806 d->target_bias_level == SND_SOC_BIAS_ON) {
1807 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1808 if (ret != 0)
1809 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
1810 ret);
1811 }
1812}
1813
1814static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1815 bool power, bool connect)
1816{
1817
1818
1819
1820 if (!connect)
1821 return;
1822
1823
1824
1825 if (power != peer->power)
1826 dapm_mark_dirty(peer, "peer state change");
1827}
1828
1829static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1830 struct list_head *up_list,
1831 struct list_head *down_list)
1832{
1833 struct snd_soc_dapm_path *path;
1834
1835 if (w->power == power)
1836 return;
1837
1838 trace_snd_soc_dapm_widget_power(w, power);
1839
1840
1841
1842
1843 snd_soc_dapm_widget_for_each_source_path(w, path)
1844 dapm_widget_set_peer_power(path->source, power, path->connect);
1845
1846
1847 if (!w->is_supply) {
1848 snd_soc_dapm_widget_for_each_sink_path(w, path)
1849 dapm_widget_set_peer_power(path->sink, power,
1850 path->connect);
1851 }
1852
1853 if (power)
1854 dapm_seq_insert(w, up_list, true);
1855 else
1856 dapm_seq_insert(w, down_list, false);
1857}
1858
1859static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1860 struct list_head *up_list,
1861 struct list_head *down_list)
1862{
1863 int power;
1864
1865 switch (w->id) {
1866 case snd_soc_dapm_pre:
1867 dapm_seq_insert(w, down_list, false);
1868 break;
1869 case snd_soc_dapm_post:
1870 dapm_seq_insert(w, up_list, true);
1871 break;
1872
1873 default:
1874 power = dapm_widget_power_check(w);
1875
1876 dapm_widget_set_power(w, power, up_list, down_list);
1877 break;
1878 }
1879}
1880
1881static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1882{
1883 if (dapm->idle_bias_off)
1884 return true;
1885
1886 switch (snd_power_get_state(dapm->card->snd_card)) {
1887 case SNDRV_CTL_POWER_D3hot:
1888 case SNDRV_CTL_POWER_D3cold:
1889 return dapm->suspend_bias_off;
1890 default:
1891 break;
1892 }
1893
1894 return false;
1895}
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906static int dapm_power_widgets(struct snd_soc_card *card, int event)
1907{
1908 struct snd_soc_dapm_widget *w;
1909 struct snd_soc_dapm_context *d;
1910 LIST_HEAD(up_list);
1911 LIST_HEAD(down_list);
1912 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
1913 enum snd_soc_bias_level bias;
1914
1915 lockdep_assert_held(&card->dapm_mutex);
1916
1917 trace_snd_soc_dapm_start(card);
1918
1919 list_for_each_entry(d, &card->dapm_list, list) {
1920 if (dapm_idle_bias_off(d))
1921 d->target_bias_level = SND_SOC_BIAS_OFF;
1922 else
1923 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1924 }
1925
1926 dapm_reset(card);
1927
1928
1929
1930
1931
1932
1933
1934 list_for_each_entry(w, &card->dapm_dirty, dirty) {
1935 dapm_power_one_widget(w, &up_list, &down_list);
1936 }
1937
1938 list_for_each_entry(w, &card->widgets, list) {
1939 switch (w->id) {
1940 case snd_soc_dapm_pre:
1941 case snd_soc_dapm_post:
1942
1943 break;
1944 default:
1945 list_del_init(&w->dirty);
1946 break;
1947 }
1948
1949 if (w->new_power) {
1950 d = w->dapm;
1951
1952
1953
1954
1955
1956
1957
1958
1959 switch (w->id) {
1960 case snd_soc_dapm_siggen:
1961 case snd_soc_dapm_vmid:
1962 break;
1963 case snd_soc_dapm_supply:
1964 case snd_soc_dapm_regulator_supply:
1965 case snd_soc_dapm_pinctrl:
1966 case snd_soc_dapm_clock_supply:
1967 case snd_soc_dapm_micbias:
1968 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1969 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1970 break;
1971 default:
1972 d->target_bias_level = SND_SOC_BIAS_ON;
1973 break;
1974 }
1975 }
1976
1977 }
1978
1979
1980
1981
1982 bias = SND_SOC_BIAS_OFF;
1983 list_for_each_entry(d, &card->dapm_list, list)
1984 if (d->target_bias_level > bias)
1985 bias = d->target_bias_level;
1986 list_for_each_entry(d, &card->dapm_list, list)
1987 if (!dapm_idle_bias_off(d))
1988 d->target_bias_level = bias;
1989
1990 trace_snd_soc_dapm_walk_done(card);
1991
1992
1993 dapm_pre_sequence_async(&card->dapm, 0);
1994
1995 list_for_each_entry(d, &card->dapm_list, list) {
1996 if (d != &card->dapm && d->bias_level != d->target_bias_level)
1997 async_schedule_domain(dapm_pre_sequence_async, d,
1998 &async_domain);
1999 }
2000 async_synchronize_full_domain(&async_domain);
2001
2002 list_for_each_entry(w, &down_list, power_list) {
2003 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
2004 }
2005
2006 list_for_each_entry(w, &up_list, power_list) {
2007 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
2008 }
2009
2010
2011 dapm_seq_run(card, &down_list, event, false);
2012
2013 dapm_widget_update(card);
2014
2015
2016 dapm_seq_run(card, &up_list, event, true);
2017
2018
2019 list_for_each_entry(d, &card->dapm_list, list) {
2020 if (d != &card->dapm && d->bias_level != d->target_bias_level)
2021 async_schedule_domain(dapm_post_sequence_async, d,
2022 &async_domain);
2023 }
2024 async_synchronize_full_domain(&async_domain);
2025
2026 dapm_post_sequence_async(&card->dapm, 0);
2027
2028
2029 list_for_each_entry(d, &card->dapm_list, list) {
2030 if (d->stream_event)
2031 d->stream_event(d, event);
2032 }
2033
2034 pop_dbg(card->dev, card->pop_time,
2035 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
2036 pop_wait(card->pop_time);
2037
2038 trace_snd_soc_dapm_done(card);
2039
2040 return 0;
2041}
2042
2043#ifdef CONFIG_DEBUG_FS
2044static ssize_t dapm_widget_power_read_file(struct file *file,
2045 char __user *user_buf,
2046 size_t count, loff_t *ppos)
2047{
2048 struct snd_soc_dapm_widget *w = file->private_data;
2049 struct snd_soc_card *card = w->dapm->card;
2050 enum snd_soc_dapm_direction dir, rdir;
2051 char *buf;
2052 int in, out;
2053 ssize_t ret;
2054 struct snd_soc_dapm_path *p = NULL;
2055
2056 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2057 if (!buf)
2058 return -ENOMEM;
2059
2060 mutex_lock(&card->dapm_mutex);
2061
2062
2063 if (w->is_supply) {
2064 in = 0;
2065 out = 0;
2066 } else {
2067 in = is_connected_input_ep(w, NULL, NULL);
2068 out = is_connected_output_ep(w, NULL, NULL);
2069 }
2070
2071 ret = scnprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
2072 w->name, w->power ? "On" : "Off",
2073 w->force ? " (forced)" : "", in, out);
2074
2075 if (w->reg >= 0)
2076 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
2077 " - R%d(0x%x) mask 0x%x",
2078 w->reg, w->reg, w->mask << w->shift);
2079
2080 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
2081
2082 if (w->sname)
2083 ret += scnprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
2084 w->sname,
2085 w->active ? "active" : "inactive");
2086
2087 snd_soc_dapm_for_each_direction(dir) {
2088 rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
2089 snd_soc_dapm_widget_for_each_path(w, dir, p) {
2090 if (p->connected && !p->connected(p->source, p->sink))
2091 continue;
2092
2093 if (!p->connect)
2094 continue;
2095
2096 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
2097 " %s \"%s\" \"%s\"\n",
2098 (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
2099 p->name ? p->name : "static",
2100 p->node[rdir]->name);
2101 }
2102 }
2103
2104 mutex_unlock(&card->dapm_mutex);
2105
2106 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
2107
2108 kfree(buf);
2109 return ret;
2110}
2111
2112static const struct file_operations dapm_widget_power_fops = {
2113 .open = simple_open,
2114 .read = dapm_widget_power_read_file,
2115 .llseek = default_llseek,
2116};
2117
2118static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
2119 size_t count, loff_t *ppos)
2120{
2121 struct snd_soc_dapm_context *dapm = file->private_data;
2122 char *level;
2123
2124 switch (dapm->bias_level) {
2125 case SND_SOC_BIAS_ON:
2126 level = "On\n";
2127 break;
2128 case SND_SOC_BIAS_PREPARE:
2129 level = "Prepare\n";
2130 break;
2131 case SND_SOC_BIAS_STANDBY:
2132 level = "Standby\n";
2133 break;
2134 case SND_SOC_BIAS_OFF:
2135 level = "Off\n";
2136 break;
2137 default:
2138 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
2139 level = "Unknown\n";
2140 break;
2141 }
2142
2143 return simple_read_from_buffer(user_buf, count, ppos, level,
2144 strlen(level));
2145}
2146
2147static const struct file_operations dapm_bias_fops = {
2148 .open = simple_open,
2149 .read = dapm_bias_read_file,
2150 .llseek = default_llseek,
2151};
2152
2153void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2154 struct dentry *parent)
2155{
2156 struct dentry *d;
2157
2158 if (!parent)
2159 return;
2160
2161 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2162
2163 if (!dapm->debugfs_dapm) {
2164 dev_warn(dapm->dev,
2165 "ASoC: Failed to create DAPM debugfs directory\n");
2166 return;
2167 }
2168
2169 d = debugfs_create_file("bias_level", 0444,
2170 dapm->debugfs_dapm, dapm,
2171 &dapm_bias_fops);
2172 if (!d)
2173 dev_warn(dapm->dev,
2174 "ASoC: Failed to create bias level debugfs file\n");
2175}
2176
2177static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2178{
2179 struct snd_soc_dapm_context *dapm = w->dapm;
2180 struct dentry *d;
2181
2182 if (!dapm->debugfs_dapm || !w->name)
2183 return;
2184
2185 d = debugfs_create_file(w->name, 0444,
2186 dapm->debugfs_dapm, w,
2187 &dapm_widget_power_fops);
2188 if (!d)
2189 dev_warn(w->dapm->dev,
2190 "ASoC: Failed to create %s debugfs file\n",
2191 w->name);
2192}
2193
2194static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2195{
2196 if (!dapm->debugfs_dapm)
2197 return;
2198 debugfs_remove_recursive(dapm->debugfs_dapm);
2199 dapm->debugfs_dapm = NULL;
2200}
2201
2202#else
2203void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2204 struct dentry *parent)
2205{
2206}
2207
2208static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2209{
2210}
2211
2212static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2213{
2214}
2215
2216#endif
2217
2218
2219
2220
2221
2222
2223
2224
2225static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2226 bool connect, const char *reason)
2227{
2228 if (path->connect == connect)
2229 return;
2230
2231 path->connect = connect;
2232 dapm_mark_dirty(path->source, reason);
2233 dapm_mark_dirty(path->sink, reason);
2234 dapm_path_invalidate(path);
2235}
2236
2237
2238static int soc_dapm_mux_update_power(struct snd_soc_card *card,
2239 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
2240{
2241 struct snd_soc_dapm_path *path;
2242 int found = 0;
2243 bool connect;
2244
2245 lockdep_assert_held(&card->dapm_mutex);
2246
2247
2248 dapm_kcontrol_for_each_path(path, kcontrol) {
2249 found = 1;
2250
2251 if (!(strcmp(path->name, e->texts[mux])))
2252 connect = true;
2253 else
2254 connect = false;
2255
2256 soc_dapm_connect_path(path, connect, "mux update");
2257 }
2258
2259 if (found)
2260 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2261
2262 return found;
2263}
2264
2265int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
2266 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2267 struct snd_soc_dapm_update *update)
2268{
2269 struct snd_soc_card *card = dapm->card;
2270 int ret;
2271
2272 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2273 card->update = update;
2274 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
2275 card->update = NULL;
2276 mutex_unlock(&card->dapm_mutex);
2277 if (ret > 0)
2278 soc_dpcm_runtime_update(card);
2279 return ret;
2280}
2281EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
2282
2283
2284static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
2285 struct snd_kcontrol *kcontrol,
2286 int connect, int rconnect)
2287{
2288 struct snd_soc_dapm_path *path;
2289 int found = 0;
2290
2291 lockdep_assert_held(&card->dapm_mutex);
2292
2293
2294 dapm_kcontrol_for_each_path(path, kcontrol) {
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317 if (found && rconnect >= 0)
2318 soc_dapm_connect_path(path, rconnect, "mixer update");
2319 else
2320 soc_dapm_connect_path(path, connect, "mixer update");
2321 found = 1;
2322 }
2323
2324 if (found)
2325 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2326
2327 return found;
2328}
2329
2330int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
2331 struct snd_kcontrol *kcontrol, int connect,
2332 struct snd_soc_dapm_update *update)
2333{
2334 struct snd_soc_card *card = dapm->card;
2335 int ret;
2336
2337 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2338 card->update = update;
2339 ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
2340 card->update = NULL;
2341 mutex_unlock(&card->dapm_mutex);
2342 if (ret > 0)
2343 soc_dpcm_runtime_update(card);
2344 return ret;
2345}
2346EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
2347
2348static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
2349 char *buf)
2350{
2351 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
2352 struct snd_soc_dapm_widget *w;
2353 int count = 0;
2354 char *state = "not set";
2355
2356
2357
2358
2359
2360 if (!cmpnt->card)
2361 return 0;
2362
2363 list_for_each_entry(w, &cmpnt->card->widgets, list) {
2364 if (w->dapm != dapm)
2365 continue;
2366
2367
2368 switch (w->id) {
2369 case snd_soc_dapm_hp:
2370 case snd_soc_dapm_mic:
2371 case snd_soc_dapm_spk:
2372 case snd_soc_dapm_line:
2373 case snd_soc_dapm_micbias:
2374 case snd_soc_dapm_dac:
2375 case snd_soc_dapm_adc:
2376 case snd_soc_dapm_pga:
2377 case snd_soc_dapm_effect:
2378 case snd_soc_dapm_out_drv:
2379 case snd_soc_dapm_mixer:
2380 case snd_soc_dapm_mixer_named_ctl:
2381 case snd_soc_dapm_supply:
2382 case snd_soc_dapm_regulator_supply:
2383 case snd_soc_dapm_pinctrl:
2384 case snd_soc_dapm_clock_supply:
2385 if (w->name)
2386 count += sprintf(buf + count, "%s: %s\n",
2387 w->name, w->power ? "On":"Off");
2388 break;
2389 default:
2390 break;
2391 }
2392 }
2393
2394 switch (snd_soc_dapm_get_bias_level(dapm)) {
2395 case SND_SOC_BIAS_ON:
2396 state = "On";
2397 break;
2398 case SND_SOC_BIAS_PREPARE:
2399 state = "Prepare";
2400 break;
2401 case SND_SOC_BIAS_STANDBY:
2402 state = "Standby";
2403 break;
2404 case SND_SOC_BIAS_OFF:
2405 state = "Off";
2406 break;
2407 }
2408 count += sprintf(buf + count, "PM State: %s\n", state);
2409
2410 return count;
2411}
2412
2413
2414static ssize_t dapm_widget_show(struct device *dev,
2415 struct device_attribute *attr, char *buf)
2416{
2417 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2418 struct snd_soc_dai *codec_dai;
2419 int i, count = 0;
2420
2421 mutex_lock(&rtd->card->dapm_mutex);
2422
2423 for_each_rtd_codec_dai(rtd, i, codec_dai) {
2424 struct snd_soc_component *cmpnt = codec_dai->component;
2425
2426 count += dapm_widget_show_component(cmpnt, buf + count);
2427 }
2428
2429 mutex_unlock(&rtd->card->dapm_mutex);
2430
2431 return count;
2432}
2433
2434static DEVICE_ATTR_RO(dapm_widget);
2435
2436struct attribute *soc_dapm_dev_attrs[] = {
2437 &dev_attr_dapm_widget.attr,
2438 NULL
2439};
2440
2441static void dapm_free_path(struct snd_soc_dapm_path *path)
2442{
2443 list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
2444 list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
2445 list_del(&path->list_kcontrol);
2446 list_del(&path->list);
2447 kfree(path);
2448}
2449
2450void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2451{
2452 struct snd_soc_dapm_path *p, *next_p;
2453 enum snd_soc_dapm_direction dir;
2454
2455 list_del(&w->list);
2456
2457
2458
2459
2460
2461 snd_soc_dapm_for_each_direction(dir) {
2462 snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
2463 dapm_free_path(p);
2464 }
2465
2466 kfree(w->kcontrols);
2467 kfree_const(w->name);
2468 kfree_const(w->sname);
2469 kfree(w);
2470}
2471
2472void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
2473{
2474 dapm->path_sink_cache.widget = NULL;
2475 dapm->path_source_cache.widget = NULL;
2476}
2477
2478
2479static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
2480{
2481 struct snd_soc_dapm_widget *w, *next_w;
2482
2483 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2484 if (w->dapm != dapm)
2485 continue;
2486 snd_soc_dapm_free_widget(w);
2487 }
2488 snd_soc_dapm_reset_cache(dapm);
2489}
2490
2491static struct snd_soc_dapm_widget *dapm_find_widget(
2492 struct snd_soc_dapm_context *dapm, const char *pin,
2493 bool search_other_contexts)
2494{
2495 struct snd_soc_dapm_widget *w;
2496 struct snd_soc_dapm_widget *fallback = NULL;
2497
2498 list_for_each_entry(w, &dapm->card->widgets, list) {
2499 if (!strcmp(w->name, pin)) {
2500 if (w->dapm == dapm)
2501 return w;
2502 else
2503 fallback = w;
2504 }
2505 }
2506
2507 if (search_other_contexts)
2508 return fallback;
2509
2510 return NULL;
2511}
2512
2513static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
2514 const char *pin, int status)
2515{
2516 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
2517
2518 dapm_assert_locked(dapm);
2519
2520 if (!w) {
2521 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
2522 return -EINVAL;
2523 }
2524
2525 if (w->connected != status) {
2526 dapm_mark_dirty(w, "pin configuration");
2527 dapm_widget_invalidate_input_paths(w);
2528 dapm_widget_invalidate_output_paths(w);
2529 }
2530
2531 w->connected = status;
2532 if (status == 0)
2533 w->force = 0;
2534
2535 return 0;
2536}
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2550{
2551
2552
2553
2554
2555 if (!dapm->card || !dapm->card->instantiated)
2556 return 0;
2557
2558 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2559}
2560EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
2572{
2573 int ret;
2574
2575 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2576 ret = snd_soc_dapm_sync_unlocked(dapm);
2577 mutex_unlock(&dapm->card->dapm_mutex);
2578 return ret;
2579}
2580EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
2581
2582static int dapm_update_dai_chan(struct snd_soc_dapm_path *p,
2583 struct snd_soc_dapm_widget *w,
2584 int channels)
2585{
2586 switch (w->id) {
2587 case snd_soc_dapm_aif_out:
2588 case snd_soc_dapm_aif_in:
2589 break;
2590 default:
2591 return 0;
2592 }
2593
2594 dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n",
2595 w->channel < channels ? "Connecting" : "Disconnecting",
2596 p->source->name, p->sink->name);
2597
2598 if (w->channel < channels)
2599 soc_dapm_connect_path(p, true, "dai update");
2600 else
2601 soc_dapm_connect_path(p, false, "dai update");
2602
2603 return 0;
2604}
2605
2606static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream,
2607 struct snd_pcm_hw_params *params,
2608 struct snd_soc_dai *dai)
2609{
2610 int dir = substream->stream;
2611 int channels = params_channels(params);
2612 struct snd_soc_dapm_path *p;
2613 struct snd_soc_dapm_widget *w;
2614 int ret;
2615
2616 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
2617 w = dai->playback_widget;
2618 else
2619 w = dai->capture_widget;
2620
2621 if (!w)
2622 return 0;
2623
2624 dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name,
2625 dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
2626
2627 snd_soc_dapm_widget_for_each_sink_path(w, p) {
2628 ret = dapm_update_dai_chan(p, p->sink, channels);
2629 if (ret < 0)
2630 return ret;
2631 }
2632
2633 snd_soc_dapm_widget_for_each_source_path(w, p) {
2634 ret = dapm_update_dai_chan(p, p->source, channels);
2635 if (ret < 0)
2636 return ret;
2637 }
2638
2639 return 0;
2640}
2641
2642int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
2643 struct snd_pcm_hw_params *params,
2644 struct snd_soc_dai *dai)
2645{
2646 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2647 int ret;
2648
2649 mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2650 ret = dapm_update_dai_unlocked(substream, params, dai);
2651 mutex_unlock(&rtd->card->dapm_mutex);
2652
2653 return ret;
2654}
2655EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2667{
2668 enum snd_soc_dapm_direction dir;
2669 struct snd_soc_dapm_path *p;
2670 unsigned int ep;
2671
2672 switch (w->id) {
2673 case snd_soc_dapm_input:
2674
2675 if (w->dapm->card->fully_routed)
2676 return;
2677 ep = SND_SOC_DAPM_EP_SOURCE;
2678 snd_soc_dapm_widget_for_each_source_path(w, p) {
2679 if (p->source->id == snd_soc_dapm_micbias ||
2680 p->source->id == snd_soc_dapm_mic ||
2681 p->source->id == snd_soc_dapm_line ||
2682 p->source->id == snd_soc_dapm_output) {
2683 ep = 0;
2684 break;
2685 }
2686 }
2687 break;
2688 case snd_soc_dapm_output:
2689
2690 if (w->dapm->card->fully_routed)
2691 return;
2692 ep = SND_SOC_DAPM_EP_SINK;
2693 snd_soc_dapm_widget_for_each_sink_path(w, p) {
2694 if (p->sink->id == snd_soc_dapm_spk ||
2695 p->sink->id == snd_soc_dapm_hp ||
2696 p->sink->id == snd_soc_dapm_line ||
2697 p->sink->id == snd_soc_dapm_input) {
2698 ep = 0;
2699 break;
2700 }
2701 }
2702 break;
2703 case snd_soc_dapm_line:
2704 ep = 0;
2705 snd_soc_dapm_for_each_direction(dir) {
2706 if (!list_empty(&w->edges[dir]))
2707 ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
2708 }
2709 break;
2710 default:
2711 return;
2712 }
2713
2714 w->is_ep = ep;
2715}
2716
2717static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2718 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2719 const char *control)
2720{
2721 bool dynamic_source = false;
2722 bool dynamic_sink = false;
2723
2724 if (!control)
2725 return 0;
2726
2727 switch (source->id) {
2728 case snd_soc_dapm_demux:
2729 dynamic_source = true;
2730 break;
2731 default:
2732 break;
2733 }
2734
2735 switch (sink->id) {
2736 case snd_soc_dapm_mux:
2737 case snd_soc_dapm_switch:
2738 case snd_soc_dapm_mixer:
2739 case snd_soc_dapm_mixer_named_ctl:
2740 dynamic_sink = true;
2741 break;
2742 default:
2743 break;
2744 }
2745
2746 if (dynamic_source && dynamic_sink) {
2747 dev_err(dapm->dev,
2748 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2749 source->name, control, sink->name);
2750 return -EINVAL;
2751 } else if (!dynamic_source && !dynamic_sink) {
2752 dev_err(dapm->dev,
2753 "Control not supported for path %s -> [%s] -> %s\n",
2754 source->name, control, sink->name);
2755 return -EINVAL;
2756 }
2757
2758 return 0;
2759}
2760
2761static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2762 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2763 const char *control,
2764 int (*connected)(struct snd_soc_dapm_widget *source,
2765 struct snd_soc_dapm_widget *sink))
2766{
2767 struct snd_soc_dapm_widget *widgets[2];
2768 enum snd_soc_dapm_direction dir;
2769 struct snd_soc_dapm_path *path;
2770 int ret;
2771
2772 if (wsink->is_supply && !wsource->is_supply) {
2773 dev_err(dapm->dev,
2774 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2775 wsource->name, wsink->name);
2776 return -EINVAL;
2777 }
2778
2779 if (connected && !wsource->is_supply) {
2780 dev_err(dapm->dev,
2781 "connected() callback only supported for supply widgets (%s -> %s)\n",
2782 wsource->name, wsink->name);
2783 return -EINVAL;
2784 }
2785
2786 if (wsource->is_supply && control) {
2787 dev_err(dapm->dev,
2788 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2789 wsource->name, control, wsink->name);
2790 return -EINVAL;
2791 }
2792
2793 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2794 if (ret)
2795 return ret;
2796
2797 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2798 if (!path)
2799 return -ENOMEM;
2800
2801 path->node[SND_SOC_DAPM_DIR_IN] = wsource;
2802 path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
2803 widgets[SND_SOC_DAPM_DIR_IN] = wsource;
2804 widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
2805
2806 path->connected = connected;
2807 INIT_LIST_HEAD(&path->list);
2808 INIT_LIST_HEAD(&path->list_kcontrol);
2809
2810 if (wsource->is_supply || wsink->is_supply)
2811 path->is_supply = 1;
2812
2813
2814 if (control == NULL) {
2815 path->connect = 1;
2816 } else {
2817 switch (wsource->id) {
2818 case snd_soc_dapm_demux:
2819 ret = dapm_connect_mux(dapm, path, control, wsource);
2820 if (ret)
2821 goto err;
2822 break;
2823 default:
2824 break;
2825 }
2826
2827 switch (wsink->id) {
2828 case snd_soc_dapm_mux:
2829 ret = dapm_connect_mux(dapm, path, control, wsink);
2830 if (ret != 0)
2831 goto err;
2832 break;
2833 case snd_soc_dapm_switch:
2834 case snd_soc_dapm_mixer:
2835 case snd_soc_dapm_mixer_named_ctl:
2836 ret = dapm_connect_mixer(dapm, path, control);
2837 if (ret != 0)
2838 goto err;
2839 break;
2840 default:
2841 break;
2842 }
2843 }
2844
2845 list_add(&path->list, &dapm->card->paths);
2846 snd_soc_dapm_for_each_direction(dir)
2847 list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
2848
2849 snd_soc_dapm_for_each_direction(dir) {
2850 dapm_update_widget_flags(widgets[dir]);
2851 dapm_mark_dirty(widgets[dir], "Route added");
2852 }
2853
2854 if (dapm->card->instantiated && path->connect)
2855 dapm_path_invalidate(path);
2856
2857 return 0;
2858err:
2859 kfree(path);
2860 return ret;
2861}
2862
2863static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
2864 const struct snd_soc_dapm_route *route)
2865{
2866 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2867 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2868 const char *sink;
2869 const char *source;
2870 char prefixed_sink[80];
2871 char prefixed_source[80];
2872 const char *prefix;
2873 unsigned int sink_ref = 0;
2874 unsigned int source_ref = 0;
2875 int ret;
2876
2877 prefix = soc_dapm_prefix(dapm);
2878 if (prefix) {
2879 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2880 prefix, route->sink);
2881 sink = prefixed_sink;
2882 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
2883 prefix, route->source);
2884 source = prefixed_source;
2885 } else {
2886 sink = route->sink;
2887 source = route->source;
2888 }
2889
2890 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2891 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2892
2893 if (wsink && wsource)
2894 goto skip_search;
2895
2896
2897
2898
2899
2900 list_for_each_entry(w, &dapm->card->widgets, list) {
2901 if (!wsink && !(strcmp(w->name, sink))) {
2902 wtsink = w;
2903 if (w->dapm == dapm) {
2904 wsink = w;
2905 if (wsource)
2906 break;
2907 }
2908 sink_ref++;
2909 if (sink_ref > 1)
2910 dev_warn(dapm->dev,
2911 "ASoC: sink widget %s overwritten\n",
2912 w->name);
2913 continue;
2914 }
2915 if (!wsource && !(strcmp(w->name, source))) {
2916 wtsource = w;
2917 if (w->dapm == dapm) {
2918 wsource = w;
2919 if (wsink)
2920 break;
2921 }
2922 source_ref++;
2923 if (source_ref > 1)
2924 dev_warn(dapm->dev,
2925 "ASoC: source widget %s overwritten\n",
2926 w->name);
2927 }
2928 }
2929
2930 if (!wsink)
2931 wsink = wtsink;
2932 if (!wsource)
2933 wsource = wtsource;
2934
2935 if (wsource == NULL) {
2936 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2937 route->source);
2938 return -ENODEV;
2939 }
2940 if (wsink == NULL) {
2941 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2942 route->sink);
2943 return -ENODEV;
2944 }
2945
2946skip_search:
2947 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2948 dapm_wcache_update(&dapm->path_source_cache, wsource);
2949
2950 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2951 route->connected);
2952 if (ret)
2953 goto err;
2954
2955 return 0;
2956err:
2957 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
2958 source, route->control, sink);
2959 return ret;
2960}
2961
2962static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2963 const struct snd_soc_dapm_route *route)
2964{
2965 struct snd_soc_dapm_widget *wsource, *wsink;
2966 struct snd_soc_dapm_path *path, *p;
2967 const char *sink;
2968 const char *source;
2969 char prefixed_sink[80];
2970 char prefixed_source[80];
2971 const char *prefix;
2972
2973 if (route->control) {
2974 dev_err(dapm->dev,
2975 "ASoC: Removal of routes with controls not supported\n");
2976 return -EINVAL;
2977 }
2978
2979 prefix = soc_dapm_prefix(dapm);
2980 if (prefix) {
2981 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2982 prefix, route->sink);
2983 sink = prefixed_sink;
2984 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
2985 prefix, route->source);
2986 source = prefixed_source;
2987 } else {
2988 sink = route->sink;
2989 source = route->source;
2990 }
2991
2992 path = NULL;
2993 list_for_each_entry(p, &dapm->card->paths, list) {
2994 if (strcmp(p->source->name, source) != 0)
2995 continue;
2996 if (strcmp(p->sink->name, sink) != 0)
2997 continue;
2998 path = p;
2999 break;
3000 }
3001
3002 if (path) {
3003 wsource = path->source;
3004 wsink = path->sink;
3005
3006 dapm_mark_dirty(wsource, "Route removed");
3007 dapm_mark_dirty(wsink, "Route removed");
3008 if (path->connect)
3009 dapm_path_invalidate(path);
3010
3011 dapm_free_path(path);
3012
3013
3014 dapm_update_widget_flags(wsource);
3015 dapm_update_widget_flags(wsink);
3016 } else {
3017 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
3018 source, sink);
3019 }
3020
3021 return 0;
3022}
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
3038 const struct snd_soc_dapm_route *route, int num)
3039{
3040 int i, r, ret = 0;
3041
3042 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3043 for (i = 0; i < num; i++) {
3044 r = snd_soc_dapm_add_route(dapm, route);
3045 if (r < 0) {
3046 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
3047 route->source,
3048 route->control ? route->control : "direct",
3049 route->sink);
3050 ret = r;
3051 }
3052 route++;
3053 }
3054 mutex_unlock(&dapm->card->dapm_mutex);
3055
3056 return ret;
3057}
3058EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
3069 const struct snd_soc_dapm_route *route, int num)
3070{
3071 int i;
3072
3073 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3074 for (i = 0; i < num; i++) {
3075 snd_soc_dapm_del_route(dapm, route);
3076 route++;
3077 }
3078 mutex_unlock(&dapm->card->dapm_mutex);
3079
3080 return 0;
3081}
3082EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
3083
3084static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
3085 const struct snd_soc_dapm_route *route)
3086{
3087 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
3088 route->source,
3089 true);
3090 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
3091 route->sink,
3092 true);
3093 struct snd_soc_dapm_path *path;
3094 int count = 0;
3095
3096 if (!source) {
3097 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
3098 route->source);
3099 return -ENODEV;
3100 }
3101
3102 if (!sink) {
3103 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
3104 route->sink);
3105 return -ENODEV;
3106 }
3107
3108 if (route->control || route->connected)
3109 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
3110 route->source, route->sink);
3111
3112 snd_soc_dapm_widget_for_each_sink_path(source, path) {
3113 if (path->sink == sink) {
3114 path->weak = 1;
3115 count++;
3116 }
3117 }
3118
3119 if (count == 0)
3120 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
3121 route->source, route->sink);
3122 if (count > 1)
3123 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
3124 count, route->source, route->sink);
3125
3126 return 0;
3127}
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
3146 const struct snd_soc_dapm_route *route, int num)
3147{
3148 int i, err;
3149 int ret = 0;
3150
3151 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
3152 for (i = 0; i < num; i++) {
3153 err = snd_soc_dapm_weak_route(dapm, route);
3154 if (err)
3155 ret = err;
3156 route++;
3157 }
3158 mutex_unlock(&dapm->card->dapm_mutex);
3159
3160 return ret;
3161}
3162EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
3173{
3174 struct snd_soc_dapm_widget *w;
3175 unsigned int val;
3176
3177 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
3178
3179 list_for_each_entry(w, &card->widgets, list)
3180 {
3181 if (w->new)
3182 continue;
3183
3184 if (w->num_kcontrols) {
3185 w->kcontrols = kcalloc(w->num_kcontrols,
3186 sizeof(struct snd_kcontrol *),
3187 GFP_KERNEL);
3188 if (!w->kcontrols) {
3189 mutex_unlock(&card->dapm_mutex);
3190 return -ENOMEM;
3191 }
3192 }
3193
3194 switch(w->id) {
3195 case snd_soc_dapm_switch:
3196 case snd_soc_dapm_mixer:
3197 case snd_soc_dapm_mixer_named_ctl:
3198 dapm_new_mixer(w);
3199 break;
3200 case snd_soc_dapm_mux:
3201 case snd_soc_dapm_demux:
3202 dapm_new_mux(w);
3203 break;
3204 case snd_soc_dapm_pga:
3205 case snd_soc_dapm_effect:
3206 case snd_soc_dapm_out_drv:
3207 dapm_new_pga(w);
3208 break;
3209 case snd_soc_dapm_dai_link:
3210 dapm_new_dai_link(w);
3211 break;
3212 default:
3213 break;
3214 }
3215
3216
3217 if (w->reg >= 0) {
3218 soc_dapm_read(w->dapm, w->reg, &val);
3219 val = val >> w->shift;
3220 val &= w->mask;
3221 if (val == w->on_val)
3222 w->power = 1;
3223 }
3224
3225 w->new = 1;
3226
3227 dapm_mark_dirty(w, "new widget");
3228 dapm_debugfs_add_widget(w);
3229 }
3230
3231 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
3232 mutex_unlock(&card->dapm_mutex);
3233 return 0;
3234}
3235EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
3247 struct snd_ctl_elem_value *ucontrol)
3248{
3249 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3250 struct snd_soc_card *card = dapm->card;
3251 struct soc_mixer_control *mc =
3252 (struct soc_mixer_control *)kcontrol->private_value;
3253 int reg = mc->reg;
3254 unsigned int shift = mc->shift;
3255 int max = mc->max;
3256 unsigned int width = fls(max);
3257 unsigned int mask = (1 << fls(max)) - 1;
3258 unsigned int invert = mc->invert;
3259 unsigned int reg_val, val, rval = 0;
3260 int ret = 0;
3261
3262 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3263 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
3264 ret = soc_dapm_read(dapm, reg, ®_val);
3265 val = (reg_val >> shift) & mask;
3266
3267 if (ret == 0 && reg != mc->rreg)
3268 ret = soc_dapm_read(dapm, mc->rreg, ®_val);
3269
3270 if (snd_soc_volsw_is_stereo(mc))
3271 rval = (reg_val >> mc->rshift) & mask;
3272 } else {
3273 reg_val = dapm_kcontrol_get_value(kcontrol);
3274 val = reg_val & mask;
3275
3276 if (snd_soc_volsw_is_stereo(mc))
3277 rval = (reg_val >> width) & mask;
3278 }
3279 mutex_unlock(&card->dapm_mutex);
3280
3281 if (ret)
3282 return ret;
3283
3284 if (invert)
3285 ucontrol->value.integer.value[0] = max - val;
3286 else
3287 ucontrol->value.integer.value[0] = val;
3288
3289 if (snd_soc_volsw_is_stereo(mc)) {
3290 if (invert)
3291 ucontrol->value.integer.value[1] = max - rval;
3292 else
3293 ucontrol->value.integer.value[1] = rval;
3294 }
3295
3296 return ret;
3297}
3298EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3310 struct snd_ctl_elem_value *ucontrol)
3311{
3312 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3313 struct snd_soc_card *card = dapm->card;
3314 struct soc_mixer_control *mc =
3315 (struct soc_mixer_control *)kcontrol->private_value;
3316 int reg = mc->reg;
3317 unsigned int shift = mc->shift;
3318 int max = mc->max;
3319 unsigned int width = fls(max);
3320 unsigned int mask = (1 << width) - 1;
3321 unsigned int invert = mc->invert;
3322 unsigned int val, rval = 0;
3323 int connect, rconnect = -1, change, reg_change = 0;
3324 struct snd_soc_dapm_update update = {};
3325 int ret = 0;
3326
3327 val = (ucontrol->value.integer.value[0] & mask);
3328 connect = !!val;
3329
3330 if (invert)
3331 val = max - val;
3332
3333 if (snd_soc_volsw_is_stereo(mc)) {
3334 rval = (ucontrol->value.integer.value[1] & mask);
3335 rconnect = !!rval;
3336 if (invert)
3337 rval = max - rval;
3338 }
3339
3340 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3341
3342
3343 if (width > sizeof(unsigned int) * 8 / 2)
3344 dev_warn(dapm->dev,
3345 "ASoC: control %s field width limit exceeded\n",
3346 kcontrol->id.name);
3347 change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
3348
3349 if (reg != SND_SOC_NOPM) {
3350 val = val << shift;
3351 rval = rval << mc->rshift;
3352
3353 reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
3354
3355 if (snd_soc_volsw_is_stereo(mc))
3356 reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
3357 mask << mc->rshift,
3358 rval);
3359 }
3360
3361 if (change || reg_change) {
3362 if (reg_change) {
3363 if (snd_soc_volsw_is_stereo(mc)) {
3364 update.has_second_set = true;
3365 update.reg2 = mc->rreg;
3366 update.mask2 = mask << mc->rshift;
3367 update.val2 = rval;
3368 }
3369 update.kcontrol = kcontrol;
3370 update.reg = reg;
3371 update.mask = mask << shift;
3372 update.val = val;
3373 card->update = &update;
3374 }
3375 change |= reg_change;
3376
3377 ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
3378 rconnect);
3379
3380 card->update = NULL;
3381 }
3382
3383 mutex_unlock(&card->dapm_mutex);
3384
3385 if (ret > 0)
3386 soc_dpcm_runtime_update(card);
3387
3388 return change;
3389}
3390EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3402 struct snd_ctl_elem_value *ucontrol)
3403{
3404 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3405 struct snd_soc_card *card = dapm->card;
3406 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3407 unsigned int reg_val, val;
3408
3409 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3410 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
3411 int ret = soc_dapm_read(dapm, e->reg, ®_val);
3412 if (ret) {
3413 mutex_unlock(&card->dapm_mutex);
3414 return ret;
3415 }
3416 } else {
3417 reg_val = dapm_kcontrol_get_value(kcontrol);
3418 }
3419 mutex_unlock(&card->dapm_mutex);
3420
3421 val = (reg_val >> e->shift_l) & e->mask;
3422 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3423 if (e->shift_l != e->shift_r) {
3424 val = (reg_val >> e->shift_r) & e->mask;
3425 val = snd_soc_enum_val_to_item(e, val);
3426 ucontrol->value.enumerated.item[1] = val;
3427 }
3428
3429 return 0;
3430}
3431EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3443 struct snd_ctl_elem_value *ucontrol)
3444{
3445 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3446 struct snd_soc_card *card = dapm->card;
3447 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3448 unsigned int *item = ucontrol->value.enumerated.item;
3449 unsigned int val, change, reg_change = 0;
3450 unsigned int mask;
3451 struct snd_soc_dapm_update update = {};
3452 int ret = 0;
3453
3454 if (item[0] >= e->items)
3455 return -EINVAL;
3456
3457 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
3458 mask = e->mask << e->shift_l;
3459 if (e->shift_l != e->shift_r) {
3460 if (item[1] > e->items)
3461 return -EINVAL;
3462 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
3463 mask |= e->mask << e->shift_r;
3464 }
3465
3466 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3467
3468 change = dapm_kcontrol_set_value(kcontrol, val);
3469
3470 if (e->reg != SND_SOC_NOPM)
3471 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3472
3473 if (change || reg_change) {
3474 if (reg_change) {
3475 update.kcontrol = kcontrol;
3476 update.reg = e->reg;
3477 update.mask = mask;
3478 update.val = val;
3479 card->update = &update;
3480 }
3481 change |= reg_change;
3482
3483 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
3484
3485 card->update = NULL;
3486 }
3487
3488 mutex_unlock(&card->dapm_mutex);
3489
3490 if (ret > 0)
3491 soc_dpcm_runtime_update(card);
3492
3493 return change;
3494}
3495EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3506 struct snd_ctl_elem_info *uinfo)
3507{
3508 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3509 uinfo->count = 1;
3510 uinfo->value.integer.min = 0;
3511 uinfo->value.integer.max = 1;
3512
3513 return 0;
3514}
3515EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3516
3517
3518
3519
3520
3521
3522
3523int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3524 struct snd_ctl_elem_value *ucontrol)
3525{
3526 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
3527 const char *pin = (const char *)kcontrol->private_value;
3528
3529 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3530
3531 ucontrol->value.integer.value[0] =
3532 snd_soc_dapm_get_pin_status(&card->dapm, pin);
3533
3534 mutex_unlock(&card->dapm_mutex);
3535
3536 return 0;
3537}
3538EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3539
3540
3541
3542
3543
3544
3545
3546int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3547 struct snd_ctl_elem_value *ucontrol)
3548{
3549 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
3550 const char *pin = (const char *)kcontrol->private_value;
3551
3552 if (ucontrol->value.integer.value[0])
3553 snd_soc_dapm_enable_pin(&card->dapm, pin);
3554 else
3555 snd_soc_dapm_disable_pin(&card->dapm, pin);
3556
3557 snd_soc_dapm_sync(&card->dapm);
3558 return 0;
3559}
3560EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3561
3562struct snd_soc_dapm_widget *
3563snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
3564 const struct snd_soc_dapm_widget *widget)
3565{
3566 enum snd_soc_dapm_direction dir;
3567 struct snd_soc_dapm_widget *w;
3568 const char *prefix;
3569 int ret;
3570
3571 if ((w = dapm_cnew_widget(widget)) == NULL)
3572 return ERR_PTR(-ENOMEM);
3573
3574 switch (w->id) {
3575 case snd_soc_dapm_regulator_supply:
3576 w->regulator = devm_regulator_get(dapm->dev, w->name);
3577 if (IS_ERR(w->regulator)) {
3578 ret = PTR_ERR(w->regulator);
3579 goto request_failed;
3580 }
3581
3582 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
3583 ret = regulator_allow_bypass(w->regulator, true);
3584 if (ret != 0)
3585 dev_warn(dapm->dev,
3586 "ASoC: Failed to bypass %s: %d\n",
3587 w->name, ret);
3588 }
3589 break;
3590 case snd_soc_dapm_pinctrl:
3591 w->pinctrl = devm_pinctrl_get(dapm->dev);
3592 if (IS_ERR(w->pinctrl)) {
3593 ret = PTR_ERR(w->pinctrl);
3594 goto request_failed;
3595 }
3596 break;
3597 case snd_soc_dapm_clock_supply:
3598 w->clk = devm_clk_get(dapm->dev, w->name);
3599 if (IS_ERR(w->clk)) {
3600 ret = PTR_ERR(w->clk);
3601 goto request_failed;
3602 }
3603 break;
3604 default:
3605 break;
3606 }
3607
3608 prefix = soc_dapm_prefix(dapm);
3609 if (prefix)
3610 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
3611 else
3612 w->name = kstrdup_const(widget->name, GFP_KERNEL);
3613 if (w->name == NULL) {
3614 kfree_const(w->sname);
3615 kfree(w);
3616 return ERR_PTR(-ENOMEM);
3617 }
3618
3619 switch (w->id) {
3620 case snd_soc_dapm_mic:
3621 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
3622 w->power_check = dapm_generic_check_power;
3623 break;
3624 case snd_soc_dapm_input:
3625 if (!dapm->card->fully_routed)
3626 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
3627 w->power_check = dapm_generic_check_power;
3628 break;
3629 case snd_soc_dapm_spk:
3630 case snd_soc_dapm_hp:
3631 w->is_ep = SND_SOC_DAPM_EP_SINK;
3632 w->power_check = dapm_generic_check_power;
3633 break;
3634 case snd_soc_dapm_output:
3635 if (!dapm->card->fully_routed)
3636 w->is_ep = SND_SOC_DAPM_EP_SINK;
3637 w->power_check = dapm_generic_check_power;
3638 break;
3639 case snd_soc_dapm_vmid:
3640 case snd_soc_dapm_siggen:
3641 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
3642 w->power_check = dapm_always_on_check_power;
3643 break;
3644 case snd_soc_dapm_sink:
3645 w->is_ep = SND_SOC_DAPM_EP_SINK;
3646 w->power_check = dapm_always_on_check_power;
3647 break;
3648
3649 case snd_soc_dapm_mux:
3650 case snd_soc_dapm_demux:
3651 case snd_soc_dapm_switch:
3652 case snd_soc_dapm_mixer:
3653 case snd_soc_dapm_mixer_named_ctl:
3654 case snd_soc_dapm_adc:
3655 case snd_soc_dapm_aif_out:
3656 case snd_soc_dapm_dac:
3657 case snd_soc_dapm_aif_in:
3658 case snd_soc_dapm_pga:
3659 case snd_soc_dapm_buffer:
3660 case snd_soc_dapm_scheduler:
3661 case snd_soc_dapm_effect:
3662 case snd_soc_dapm_src:
3663 case snd_soc_dapm_asrc:
3664 case snd_soc_dapm_encoder:
3665 case snd_soc_dapm_decoder:
3666 case snd_soc_dapm_out_drv:
3667 case snd_soc_dapm_micbias:
3668 case snd_soc_dapm_line:
3669 case snd_soc_dapm_dai_link:
3670 case snd_soc_dapm_dai_out:
3671 case snd_soc_dapm_dai_in:
3672 w->power_check = dapm_generic_check_power;
3673 break;
3674 case snd_soc_dapm_supply:
3675 case snd_soc_dapm_regulator_supply:
3676 case snd_soc_dapm_pinctrl:
3677 case snd_soc_dapm_clock_supply:
3678 case snd_soc_dapm_kcontrol:
3679 w->is_supply = 1;
3680 w->power_check = dapm_supply_check_power;
3681 break;
3682 default:
3683 w->power_check = dapm_always_on_check_power;
3684 break;
3685 }
3686
3687 w->dapm = dapm;
3688 INIT_LIST_HEAD(&w->list);
3689 INIT_LIST_HEAD(&w->dirty);
3690 list_add_tail(&w->list, &dapm->card->widgets);
3691
3692 snd_soc_dapm_for_each_direction(dir) {
3693 INIT_LIST_HEAD(&w->edges[dir]);
3694 w->endpoints[dir] = -1;
3695 }
3696
3697
3698 w->connected = 1;
3699 return w;
3700
3701request_failed:
3702 if (ret != -EPROBE_DEFER)
3703 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
3704 w->name, ret);
3705
3706 return ERR_PTR(ret);
3707}
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718struct snd_soc_dapm_widget *
3719snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3720 const struct snd_soc_dapm_widget *widget)
3721{
3722 struct snd_soc_dapm_widget *w;
3723
3724 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3725 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3726 mutex_unlock(&dapm->card->dapm_mutex);
3727
3728 return w;
3729}
3730EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
3743 const struct snd_soc_dapm_widget *widget,
3744 int num)
3745{
3746 struct snd_soc_dapm_widget *w;
3747 int i;
3748 int ret = 0;
3749
3750 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
3751 for (i = 0; i < num; i++) {
3752 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3753 if (IS_ERR(w)) {
3754 ret = PTR_ERR(w);
3755 break;
3756 }
3757 widget++;
3758 }
3759 mutex_unlock(&dapm->card->dapm_mutex);
3760 return ret;
3761}
3762EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3763
3764static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3765 struct snd_kcontrol *kcontrol, int event)
3766{
3767 struct snd_soc_dapm_path *path;
3768 struct snd_soc_dai *source, *sink;
3769 struct snd_soc_pcm_runtime *rtd = w->priv;
3770 const struct snd_soc_pcm_stream *config;
3771 struct snd_pcm_substream substream;
3772 struct snd_pcm_hw_params *params = NULL;
3773 struct snd_pcm_runtime *runtime = NULL;
3774 unsigned int fmt;
3775 int ret = 0;
3776
3777 config = rtd->dai_link->params + rtd->params_select;
3778
3779 if (WARN_ON(!config) ||
3780 WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3781 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
3782 return -EINVAL;
3783
3784
3785 if (config->formats) {
3786 fmt = ffs(config->formats) - 1;
3787 } else {
3788 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
3789 config->formats);
3790 fmt = 0;
3791 }
3792
3793
3794 params = kzalloc(sizeof(*params), GFP_KERNEL);
3795 if (!params) {
3796 ret = -ENOMEM;
3797 goto out;
3798 }
3799 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
3800
3801 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
3802 config->rate_min;
3803 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
3804 config->rate_max;
3805
3806 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
3807 = config->channels_min;
3808 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
3809 = config->channels_max;
3810
3811 memset(&substream, 0, sizeof(substream));
3812
3813
3814 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
3815 if (!runtime) {
3816 ret = -ENOMEM;
3817 goto out;
3818 }
3819 substream.runtime = runtime;
3820 substream.private_data = rtd;
3821
3822 switch (event) {
3823 case SND_SOC_DAPM_PRE_PMU:
3824 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3825 snd_soc_dapm_widget_for_each_source_path(w, path) {
3826 source = path->source->priv;
3827
3828 if (source->driver->ops->startup) {
3829 ret = source->driver->ops->startup(&substream,
3830 source);
3831 if (ret < 0) {
3832 dev_err(source->dev,
3833 "ASoC: startup() failed: %d\n",
3834 ret);
3835 goto out;
3836 }
3837 }
3838 source->active++;
3839 ret = soc_dai_hw_params(&substream, params, source);
3840 if (ret < 0)
3841 goto out;
3842
3843 dapm_update_dai_unlocked(&substream, params, source);
3844 }
3845
3846 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3847 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3848 sink = path->sink->priv;
3849
3850 if (sink->driver->ops->startup) {
3851 ret = sink->driver->ops->startup(&substream,
3852 sink);
3853 if (ret < 0) {
3854 dev_err(sink->dev,
3855 "ASoC: startup() failed: %d\n",
3856 ret);
3857 goto out;
3858 }
3859 }
3860 sink->active++;
3861 ret = soc_dai_hw_params(&substream, params, sink);
3862 if (ret < 0)
3863 goto out;
3864
3865 dapm_update_dai_unlocked(&substream, params, sink);
3866 }
3867 break;
3868
3869 case SND_SOC_DAPM_POST_PMU:
3870 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3871 sink = path->sink->priv;
3872
3873 ret = snd_soc_dai_digital_mute(sink, 0,
3874 SNDRV_PCM_STREAM_PLAYBACK);
3875 if (ret != 0 && ret != -ENOTSUPP)
3876 dev_warn(sink->dev,
3877 "ASoC: Failed to unmute: %d\n", ret);
3878 ret = 0;
3879 }
3880 break;
3881
3882 case SND_SOC_DAPM_PRE_PMD:
3883 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3884 sink = path->sink->priv;
3885
3886 ret = snd_soc_dai_digital_mute(sink, 1,
3887 SNDRV_PCM_STREAM_PLAYBACK);
3888 if (ret != 0 && ret != -ENOTSUPP)
3889 dev_warn(sink->dev,
3890 "ASoC: Failed to mute: %d\n", ret);
3891 ret = 0;
3892 }
3893
3894 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3895 snd_soc_dapm_widget_for_each_source_path(w, path) {
3896 source = path->source->priv;
3897
3898 if (source->driver->ops->hw_free)
3899 source->driver->ops->hw_free(&substream,
3900 source);
3901
3902 source->active--;
3903 if (source->driver->ops->shutdown)
3904 source->driver->ops->shutdown(&substream,
3905 source);
3906 }
3907
3908 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3909 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3910 sink = path->sink->priv;
3911
3912 if (sink->driver->ops->hw_free)
3913 sink->driver->ops->hw_free(&substream, sink);
3914
3915 sink->active--;
3916 if (sink->driver->ops->shutdown)
3917 sink->driver->ops->shutdown(&substream, sink);
3918 }
3919 break;
3920
3921 default:
3922 WARN(1, "Unknown event %d\n", event);
3923 ret = -EINVAL;
3924 }
3925
3926out:
3927 kfree(runtime);
3928 kfree(params);
3929 return ret;
3930}
3931
3932static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3933 struct snd_ctl_elem_value *ucontrol)
3934{
3935 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3936 struct snd_soc_pcm_runtime *rtd = w->priv;
3937
3938 ucontrol->value.enumerated.item[0] = rtd->params_select;
3939
3940 return 0;
3941}
3942
3943static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3944 struct snd_ctl_elem_value *ucontrol)
3945{
3946 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3947 struct snd_soc_pcm_runtime *rtd = w->priv;
3948
3949
3950 if (w->power)
3951 return -EBUSY;
3952
3953 if (ucontrol->value.enumerated.item[0] == rtd->params_select)
3954 return 0;
3955
3956 if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params)
3957 return -EINVAL;
3958
3959 rtd->params_select = ucontrol->value.enumerated.item[0];
3960
3961 return 0;
3962}
3963
3964static void
3965snd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
3966 unsigned long *private_value,
3967 int num_params,
3968 const char **w_param_text)
3969{
3970 int count;
3971
3972 devm_kfree(card->dev, (void *)*private_value);
3973
3974 if (!w_param_text)
3975 return;
3976
3977 for (count = 0 ; count < num_params; count++)
3978 devm_kfree(card->dev, (void *)w_param_text[count]);
3979 devm_kfree(card->dev, w_param_text);
3980}
3981
3982static struct snd_kcontrol_new *
3983snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
3984 char *link_name,
3985 const struct snd_soc_pcm_stream *params,
3986 int num_params, const char **w_param_text,
3987 unsigned long *private_value)
3988{
3989 struct soc_enum w_param_enum[] = {
3990 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3991 };
3992 struct snd_kcontrol_new kcontrol_dai_link[] = {
3993 SOC_ENUM_EXT(NULL, w_param_enum[0],
3994 snd_soc_dapm_dai_link_get,
3995 snd_soc_dapm_dai_link_put),
3996 };
3997 struct snd_kcontrol_new *kcontrol_news;
3998 const struct snd_soc_pcm_stream *config = params;
3999 int count;
4000
4001 for (count = 0 ; count < num_params; count++) {
4002 if (!config->stream_name) {
4003 dev_warn(card->dapm.dev,
4004 "ASoC: anonymous config %d for dai link %s\n",
4005 count, link_name);
4006 w_param_text[count] =
4007 devm_kasprintf(card->dev, GFP_KERNEL,
4008 "Anonymous Configuration %d",
4009 count);
4010 } else {
4011 w_param_text[count] = devm_kmemdup(card->dev,
4012 config->stream_name,
4013 strlen(config->stream_name) + 1,
4014 GFP_KERNEL);
4015 }
4016 if (!w_param_text[count])
4017 goto outfree_w_param;
4018 config++;
4019 }
4020
4021 w_param_enum[0].items = num_params;
4022 w_param_enum[0].texts = w_param_text;
4023
4024 *private_value =
4025 (unsigned long) devm_kmemdup(card->dev,
4026 (void *)(kcontrol_dai_link[0].private_value),
4027 sizeof(struct soc_enum), GFP_KERNEL);
4028 if (!*private_value) {
4029 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
4030 link_name);
4031 goto outfree_w_param;
4032 }
4033 kcontrol_dai_link[0].private_value = *private_value;
4034
4035 kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
4036 sizeof(struct snd_kcontrol_new),
4037 GFP_KERNEL);
4038 if (!kcontrol_news) {
4039 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
4040 link_name);
4041 goto outfree_w_param;
4042 }
4043 return kcontrol_news;
4044
4045outfree_w_param:
4046 snd_soc_dapm_free_kcontrol(card, private_value, num_params, w_param_text);
4047 return NULL;
4048}
4049
4050static struct snd_soc_dapm_widget *
4051snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd,
4052 struct snd_soc_dapm_widget *source,
4053 struct snd_soc_dapm_widget *sink)
4054{
4055 struct snd_soc_dapm_widget template;
4056 struct snd_soc_dapm_widget *w;
4057 const char **w_param_text;
4058 unsigned long private_value = 0;
4059 char *link_name;
4060 int ret;
4061
4062 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
4063 source->name, sink->name);
4064 if (!link_name)
4065 return ERR_PTR(-ENOMEM);
4066
4067 memset(&template, 0, sizeof(template));
4068 template.reg = SND_SOC_NOPM;
4069 template.id = snd_soc_dapm_dai_link;
4070 template.name = link_name;
4071 template.event = snd_soc_dai_link_event;
4072 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4073 SND_SOC_DAPM_PRE_PMD;
4074 template.kcontrol_news = NULL;
4075
4076
4077 if (rtd->dai_link->num_params > 1) {
4078 w_param_text = devm_kcalloc(card->dev,
4079 rtd->dai_link->num_params,
4080 sizeof(char *), GFP_KERNEL);
4081 if (!w_param_text) {
4082 ret = -ENOMEM;
4083 goto param_fail;
4084 }
4085
4086 template.num_kcontrols = 1;
4087 template.kcontrol_news =
4088 snd_soc_dapm_alloc_kcontrol(card,
4089 link_name,
4090 rtd->dai_link->params,
4091 rtd->dai_link->num_params,
4092 w_param_text, &private_value);
4093 if (!template.kcontrol_news) {
4094 ret = -ENOMEM;
4095 goto param_fail;
4096 }
4097 } else {
4098 w_param_text = NULL;
4099 }
4100 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
4101
4102 w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
4103 if (IS_ERR(w)) {
4104 ret = PTR_ERR(w);
4105 goto outfree_kcontrol_news;
4106 }
4107
4108 w->priv = rtd;
4109
4110 return w;
4111
4112outfree_kcontrol_news:
4113 devm_kfree(card->dev, (void *)template.kcontrol_news);
4114 snd_soc_dapm_free_kcontrol(card, &private_value,
4115 rtd->dai_link->num_params, w_param_text);
4116param_fail:
4117 devm_kfree(card->dev, link_name);
4118 return ERR_PTR(ret);
4119}
4120
4121int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
4122 struct snd_soc_dai *dai)
4123{
4124 struct snd_soc_dapm_widget template;
4125 struct snd_soc_dapm_widget *w;
4126
4127 WARN_ON(dapm->dev != dai->dev);
4128
4129 memset(&template, 0, sizeof(template));
4130 template.reg = SND_SOC_NOPM;
4131
4132 if (dai->driver->playback.stream_name) {
4133 template.id = snd_soc_dapm_dai_in;
4134 template.name = dai->driver->playback.stream_name;
4135 template.sname = dai->driver->playback.stream_name;
4136
4137 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
4138 template.name);
4139
4140 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
4141 if (IS_ERR(w))
4142 return PTR_ERR(w);
4143
4144 w->priv = dai;
4145 dai->playback_widget = w;
4146 }
4147
4148 if (dai->driver->capture.stream_name) {
4149 template.id = snd_soc_dapm_dai_out;
4150 template.name = dai->driver->capture.stream_name;
4151 template.sname = dai->driver->capture.stream_name;
4152
4153 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
4154 template.name);
4155
4156 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
4157 if (IS_ERR(w))
4158 return PTR_ERR(w);
4159
4160 w->priv = dai;
4161 dai->capture_widget = w;
4162 }
4163
4164 return 0;
4165}
4166
4167int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
4168{
4169 struct snd_soc_dapm_widget *dai_w, *w;
4170 struct snd_soc_dapm_widget *src, *sink;
4171 struct snd_soc_dai *dai;
4172
4173
4174 list_for_each_entry(dai_w, &card->widgets, list) {
4175 switch (dai_w->id) {
4176 case snd_soc_dapm_dai_in:
4177 case snd_soc_dapm_dai_out:
4178 break;
4179 default:
4180 continue;
4181 }
4182
4183
4184 if (!dai_w->priv) {
4185 dev_dbg(card->dev, "dai widget %s has no DAI\n",
4186 dai_w->name);
4187 continue;
4188 }
4189
4190 dai = dai_w->priv;
4191
4192
4193 list_for_each_entry(w, &card->widgets, list) {
4194 if (w->dapm != dai_w->dapm)
4195 continue;
4196
4197 switch (w->id) {
4198 case snd_soc_dapm_dai_in:
4199 case snd_soc_dapm_dai_out:
4200 continue;
4201 default:
4202 break;
4203 }
4204
4205 if (!w->sname || !strstr(w->sname, dai_w->sname))
4206 continue;
4207
4208 if (dai_w->id == snd_soc_dapm_dai_in) {
4209 src = dai_w;
4210 sink = w;
4211 } else {
4212 src = w;
4213 sink = dai_w;
4214 }
4215 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
4216 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
4217 }
4218 }
4219
4220 return 0;
4221}
4222
4223static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
4224 struct snd_soc_pcm_runtime *rtd)
4225{
4226 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
4227 struct snd_soc_dai *codec_dai;
4228 struct snd_soc_dapm_widget *playback = NULL, *capture = NULL;
4229 struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu;
4230 int i;
4231
4232 if (rtd->dai_link->params) {
4233 playback_cpu = cpu_dai->capture_widget;
4234 capture_cpu = cpu_dai->playback_widget;
4235 } else {
4236 playback = cpu_dai->playback_widget;
4237 capture = cpu_dai->capture_widget;
4238 playback_cpu = playback;
4239 capture_cpu = capture;
4240 }
4241
4242 for_each_rtd_codec_dai(rtd, i, codec_dai) {
4243
4244
4245 codec = codec_dai->playback_widget;
4246
4247 if (playback_cpu && codec) {
4248 if (!playback) {
4249 playback = snd_soc_dapm_new_dai(card, rtd,
4250 playback_cpu,
4251 codec);
4252 if (IS_ERR(playback)) {
4253 dev_err(rtd->dev,
4254 "ASoC: Failed to create DAI %s: %ld\n",
4255 codec_dai->name,
4256 PTR_ERR(playback));
4257 continue;
4258 }
4259
4260 snd_soc_dapm_add_path(&card->dapm, playback_cpu,
4261 playback, NULL, NULL);
4262 }
4263
4264 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
4265 cpu_dai->component->name, playback_cpu->name,
4266 codec_dai->component->name, codec->name);
4267
4268 snd_soc_dapm_add_path(&card->dapm, playback, codec,
4269 NULL, NULL);
4270 }
4271 }
4272
4273 for_each_rtd_codec_dai(rtd, i, codec_dai) {
4274
4275 codec = codec_dai->capture_widget;
4276
4277 if (codec && capture_cpu) {
4278 if (!capture) {
4279 capture = snd_soc_dapm_new_dai(card, rtd,
4280 codec,
4281 capture_cpu);
4282 if (IS_ERR(capture)) {
4283 dev_err(rtd->dev,
4284 "ASoC: Failed to create DAI %s: %ld\n",
4285 codec_dai->name,
4286 PTR_ERR(capture));
4287 continue;
4288 }
4289
4290 snd_soc_dapm_add_path(&card->dapm, capture,
4291 capture_cpu, NULL, NULL);
4292 }
4293
4294 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
4295 codec_dai->component->name, codec->name,
4296 cpu_dai->component->name, capture_cpu->name);
4297
4298 snd_soc_dapm_add_path(&card->dapm, codec, capture,
4299 NULL, NULL);
4300 }
4301 }
4302}
4303
4304static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
4305 int event)
4306{
4307 struct snd_soc_dapm_widget *w;
4308 unsigned int ep;
4309
4310 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
4311 w = dai->playback_widget;
4312 else
4313 w = dai->capture_widget;
4314
4315 if (w) {
4316 dapm_mark_dirty(w, "stream event");
4317
4318 if (w->id == snd_soc_dapm_dai_in) {
4319 ep = SND_SOC_DAPM_EP_SOURCE;
4320 dapm_widget_invalidate_input_paths(w);
4321 } else {
4322 ep = SND_SOC_DAPM_EP_SINK;
4323 dapm_widget_invalidate_output_paths(w);
4324 }
4325
4326 switch (event) {
4327 case SND_SOC_DAPM_STREAM_START:
4328 w->active = 1;
4329 w->is_ep = ep;
4330 break;
4331 case SND_SOC_DAPM_STREAM_STOP:
4332 w->active = 0;
4333 w->is_ep = 0;
4334 break;
4335 case SND_SOC_DAPM_STREAM_SUSPEND:
4336 case SND_SOC_DAPM_STREAM_RESUME:
4337 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
4338 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
4339 break;
4340 }
4341 }
4342}
4343
4344void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
4345{
4346 struct snd_soc_pcm_runtime *rtd;
4347
4348
4349 for_each_card_rtds(card, rtd) {
4350
4351
4352
4353
4354 if (rtd->dai_link->dynamic)
4355 continue;
4356
4357 dapm_connect_dai_link_widgets(card, rtd);
4358 }
4359}
4360
4361static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4362 int event)
4363{
4364 struct snd_soc_dai *codec_dai;
4365 int i;
4366
4367 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
4368 for_each_rtd_codec_dai(rtd, i, codec_dai)
4369 soc_dapm_dai_stream_event(codec_dai, stream, event);
4370
4371 dapm_power_widgets(rtd->card, event);
4372}
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4386 int event)
4387{
4388 struct snd_soc_card *card = rtd->card;
4389
4390 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4391 soc_dapm_stream_event(rtd, stream, event);
4392 mutex_unlock(&card->dapm_mutex);
4393}
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4409 const char *pin)
4410{
4411 return snd_soc_dapm_set_pin(dapm, pin, 1);
4412}
4413EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
4427{
4428 int ret;
4429
4430 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4431
4432 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
4433
4434 mutex_unlock(&dapm->card->dapm_mutex);
4435
4436 return ret;
4437}
4438EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4455 const char *pin)
4456{
4457 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4458
4459 if (!w) {
4460 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4461 return -EINVAL;
4462 }
4463
4464 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
4465 if (!w->connected) {
4466
4467
4468
4469
4470 dapm_widget_invalidate_input_paths(w);
4471 dapm_widget_invalidate_output_paths(w);
4472 w->connected = 1;
4473 }
4474 w->force = 1;
4475 dapm_mark_dirty(w, "force enable");
4476
4477 return 0;
4478}
4479EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4494 const char *pin)
4495{
4496 int ret;
4497
4498 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4499
4500 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
4501
4502 mutex_unlock(&dapm->card->dapm_mutex);
4503
4504 return ret;
4505}
4506EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4521 const char *pin)
4522{
4523 return snd_soc_dapm_set_pin(dapm, pin, 0);
4524}
4525EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4538 const char *pin)
4539{
4540 int ret;
4541
4542 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4543
4544 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4545
4546 mutex_unlock(&dapm->card->dapm_mutex);
4547
4548 return ret;
4549}
4550EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4569 const char *pin)
4570{
4571 return snd_soc_dapm_set_pin(dapm, pin, 0);
4572}
4573EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
4590{
4591 int ret;
4592
4593 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4594
4595 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4596
4597 mutex_unlock(&dapm->card->dapm_mutex);
4598
4599 return ret;
4600}
4601EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4613 const char *pin)
4614{
4615 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4616
4617 if (w)
4618 return w->connected;
4619
4620 return 0;
4621}
4622EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4636 const char *pin)
4637{
4638 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
4639
4640 if (!w) {
4641 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4642 return -EINVAL;
4643 }
4644
4645 w->ignore_suspend = 1;
4646
4647 return 0;
4648}
4649EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4650
4651
4652
4653
4654
4655
4656
4657void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
4658{
4659 dapm_debugfs_cleanup(dapm);
4660 dapm_free_widgets(dapm);
4661 list_del(&dapm->list);
4662}
4663EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4664
4665static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
4666{
4667 struct snd_soc_card *card = dapm->card;
4668 struct snd_soc_dapm_widget *w;
4669 LIST_HEAD(down_list);
4670 int powerdown = 0;
4671
4672 mutex_lock(&card->dapm_mutex);
4673
4674 list_for_each_entry(w, &dapm->card->widgets, list) {
4675 if (w->dapm != dapm)
4676 continue;
4677 if (w->power) {
4678 dapm_seq_insert(w, &down_list, false);
4679 w->power = 0;
4680 powerdown = 1;
4681 }
4682 }
4683
4684
4685
4686
4687 if (powerdown) {
4688 if (dapm->bias_level == SND_SOC_BIAS_ON)
4689 snd_soc_dapm_set_bias_level(dapm,
4690 SND_SOC_BIAS_PREPARE);
4691 dapm_seq_run(card, &down_list, 0, false);
4692 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4693 snd_soc_dapm_set_bias_level(dapm,
4694 SND_SOC_BIAS_STANDBY);
4695 }
4696
4697 mutex_unlock(&card->dapm_mutex);
4698}
4699
4700
4701
4702
4703void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4704{
4705 struct snd_soc_dapm_context *dapm;
4706
4707 list_for_each_entry(dapm, &card->dapm_list, list) {
4708 if (dapm != &card->dapm) {
4709 soc_dapm_shutdown_dapm(dapm);
4710 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4711 snd_soc_dapm_set_bias_level(dapm,
4712 SND_SOC_BIAS_OFF);
4713 }
4714 }
4715
4716 soc_dapm_shutdown_dapm(&card->dapm);
4717 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4718 snd_soc_dapm_set_bias_level(&card->dapm,
4719 SND_SOC_BIAS_OFF);
4720}
4721
4722
4723MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
4724MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4725MODULE_LICENSE("GPL");
4726