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