diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 604 |
1 files changed, 275 insertions, 329 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dc8ff13187f7..c8a780d0d057 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -70,8 +70,6 @@ static int dapm_up_seq[] = { | |||
70 | [snd_soc_dapm_aif_out] = 4, | 70 | [snd_soc_dapm_aif_out] = 4, |
71 | [snd_soc_dapm_mic] = 5, | 71 | [snd_soc_dapm_mic] = 5, |
72 | [snd_soc_dapm_mux] = 6, | 72 | [snd_soc_dapm_mux] = 6, |
73 | [snd_soc_dapm_virt_mux] = 6, | ||
74 | [snd_soc_dapm_value_mux] = 6, | ||
75 | [snd_soc_dapm_dac] = 7, | 73 | [snd_soc_dapm_dac] = 7, |
76 | [snd_soc_dapm_switch] = 8, | 74 | [snd_soc_dapm_switch] = 8, |
77 | [snd_soc_dapm_mixer] = 8, | 75 | [snd_soc_dapm_mixer] = 8, |
@@ -102,8 +100,6 @@ static int dapm_down_seq[] = { | |||
102 | [snd_soc_dapm_mic] = 7, | 100 | [snd_soc_dapm_mic] = 7, |
103 | [snd_soc_dapm_micbias] = 8, | 101 | [snd_soc_dapm_micbias] = 8, |
104 | [snd_soc_dapm_mux] = 9, | 102 | [snd_soc_dapm_mux] = 9, |
105 | [snd_soc_dapm_virt_mux] = 9, | ||
106 | [snd_soc_dapm_value_mux] = 9, | ||
107 | [snd_soc_dapm_aif_in] = 10, | 103 | [snd_soc_dapm_aif_in] = 10, |
108 | [snd_soc_dapm_aif_out] = 10, | 104 | [snd_soc_dapm_aif_out] = 10, |
109 | [snd_soc_dapm_dai_in] = 10, | 105 | [snd_soc_dapm_dai_in] = 10, |
@@ -115,6 +111,12 @@ static int dapm_down_seq[] = { | |||
115 | [snd_soc_dapm_post] = 14, | 111 | [snd_soc_dapm_post] = 14, |
116 | }; | 112 | }; |
117 | 113 | ||
114 | static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) | ||
115 | { | ||
116 | if (dapm->card && dapm->card->instantiated) | ||
117 | lockdep_assert_held(&dapm->card->dapm_mutex); | ||
118 | } | ||
119 | |||
118 | static void pop_wait(u32 pop_time) | 120 | static void pop_wait(u32 pop_time) |
119 | { | 121 | { |
120 | if (pop_time) | 122 | if (pop_time) |
@@ -146,15 +148,16 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w) | |||
146 | return !list_empty(&w->dirty); | 148 | return !list_empty(&w->dirty); |
147 | } | 149 | } |
148 | 150 | ||
149 | void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) | 151 | static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) |
150 | { | 152 | { |
153 | dapm_assert_locked(w->dapm); | ||
154 | |||
151 | if (!dapm_dirty_widget(w)) { | 155 | if (!dapm_dirty_widget(w)) { |
152 | dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", | 156 | dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", |
153 | w->name, reason); | 157 | w->name, reason); |
154 | list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); | 158 | list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); |
155 | } | 159 | } |
156 | } | 160 | } |
157 | EXPORT_SYMBOL_GPL(dapm_mark_dirty); | ||
158 | 161 | ||
159 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) | 162 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) |
160 | { | 163 | { |
@@ -361,6 +364,8 @@ static void dapm_reset(struct snd_soc_card *card) | |||
361 | { | 364 | { |
362 | struct snd_soc_dapm_widget *w; | 365 | struct snd_soc_dapm_widget *w; |
363 | 366 | ||
367 | lockdep_assert_held(&card->dapm_mutex); | ||
368 | |||
364 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | 369 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); |
365 | 370 | ||
366 | list_for_each_entry(w, &card->widgets, list) { | 371 | list_for_each_entry(w, &card->widgets, list) { |
@@ -386,7 +391,8 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, | |||
386 | return -1; | 391 | return -1; |
387 | } | 392 | } |
388 | 393 | ||
389 | static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) | 394 | static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, |
395 | unsigned int val) | ||
390 | { | 396 | { |
391 | if (w->codec) | 397 | if (w->codec) |
392 | return snd_soc_write(w->codec, reg, val); | 398 | return snd_soc_write(w->codec, reg, val); |
@@ -498,131 +504,40 @@ out: | |||
498 | return ret; | 504 | return ret; |
499 | } | 505 | } |
500 | 506 | ||
501 | /* set up initial codec paths */ | 507 | /* connect mux widget to its interconnecting audio paths */ |
502 | static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | 508 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
503 | struct snd_soc_dapm_path *p, int i) | 509 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
510 | struct snd_soc_dapm_path *path, const char *control_name, | ||
511 | const struct snd_kcontrol_new *kcontrol) | ||
504 | { | 512 | { |
505 | switch (w->id) { | 513 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
506 | case snd_soc_dapm_switch: | 514 | unsigned int val, item; |
507 | case snd_soc_dapm_mixer: | 515 | int i; |
508 | case snd_soc_dapm_mixer_named_ctl: { | ||
509 | int val; | ||
510 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | ||
511 | w->kcontrol_news[i].private_value; | ||
512 | int reg = mc->reg; | ||
513 | unsigned int shift = mc->shift; | ||
514 | int max = mc->max; | ||
515 | unsigned int mask = (1 << fls(max)) - 1; | ||
516 | unsigned int invert = mc->invert; | ||
517 | |||
518 | if (reg != SND_SOC_NOPM) { | ||
519 | soc_widget_read(w, reg, &val); | ||
520 | val = (val >> shift) & mask; | ||
521 | if (invert) | ||
522 | val = max - val; | ||
523 | p->connect = !!val; | ||
524 | } else { | ||
525 | p->connect = 0; | ||
526 | } | ||
527 | |||
528 | } | ||
529 | break; | ||
530 | case snd_soc_dapm_mux: { | ||
531 | struct soc_enum *e = (struct soc_enum *) | ||
532 | w->kcontrol_news[i].private_value; | ||
533 | int val, item; | ||
534 | |||
535 | soc_widget_read(w, e->reg, &val); | ||
536 | item = (val >> e->shift_l) & e->mask; | ||
537 | |||
538 | if (item < e->max && !strcmp(p->name, e->texts[item])) | ||
539 | p->connect = 1; | ||
540 | else | ||
541 | p->connect = 0; | ||
542 | } | ||
543 | break; | ||
544 | case snd_soc_dapm_virt_mux: { | ||
545 | struct soc_enum *e = (struct soc_enum *) | ||
546 | w->kcontrol_news[i].private_value; | ||
547 | 516 | ||
548 | p->connect = 0; | 517 | if (e->reg != SND_SOC_NOPM) { |
518 | soc_widget_read(dest, e->reg, &val); | ||
519 | val = (val >> e->shift_l) & e->mask; | ||
520 | item = snd_soc_enum_val_to_item(e, val); | ||
521 | } else { | ||
549 | /* since a virtual mux has no backing registers to | 522 | /* since a virtual mux has no backing registers to |
550 | * decide which path to connect, it will try to match | 523 | * decide which path to connect, it will try to match |
551 | * with the first enumeration. This is to ensure | 524 | * with the first enumeration. This is to ensure |
552 | * that the default mux choice (the first) will be | 525 | * that the default mux choice (the first) will be |
553 | * correctly powered up during initialization. | 526 | * correctly powered up during initialization. |
554 | */ | 527 | */ |
555 | if (!strcmp(p->name, e->texts[0])) | 528 | item = 0; |
556 | p->connect = 1; | ||
557 | } | ||
558 | break; | ||
559 | case snd_soc_dapm_value_mux: { | ||
560 | struct soc_enum *e = (struct soc_enum *) | ||
561 | w->kcontrol_news[i].private_value; | ||
562 | int val, item; | ||
563 | |||
564 | soc_widget_read(w, e->reg, &val); | ||
565 | val = (val >> e->shift_l) & e->mask; | ||
566 | for (item = 0; item < e->max; item++) { | ||
567 | if (val == e->values[item]) | ||
568 | break; | ||
569 | } | ||
570 | |||
571 | if (item < e->max && !strcmp(p->name, e->texts[item])) | ||
572 | p->connect = 1; | ||
573 | else | ||
574 | p->connect = 0; | ||
575 | } | ||
576 | break; | ||
577 | /* does not affect routing - always connected */ | ||
578 | case snd_soc_dapm_pga: | ||
579 | case snd_soc_dapm_out_drv: | ||
580 | case snd_soc_dapm_output: | ||
581 | case snd_soc_dapm_adc: | ||
582 | case snd_soc_dapm_input: | ||
583 | case snd_soc_dapm_siggen: | ||
584 | case snd_soc_dapm_dac: | ||
585 | case snd_soc_dapm_micbias: | ||
586 | case snd_soc_dapm_vmid: | ||
587 | case snd_soc_dapm_supply: | ||
588 | case snd_soc_dapm_regulator_supply: | ||
589 | case snd_soc_dapm_clock_supply: | ||
590 | case snd_soc_dapm_aif_in: | ||
591 | case snd_soc_dapm_aif_out: | ||
592 | case snd_soc_dapm_dai_in: | ||
593 | case snd_soc_dapm_dai_out: | ||
594 | case snd_soc_dapm_hp: | ||
595 | case snd_soc_dapm_mic: | ||
596 | case snd_soc_dapm_spk: | ||
597 | case snd_soc_dapm_line: | ||
598 | case snd_soc_dapm_dai_link: | ||
599 | case snd_soc_dapm_kcontrol: | ||
600 | p->connect = 1; | ||
601 | break; | ||
602 | /* does affect routing - dynamically connected */ | ||
603 | case snd_soc_dapm_pre: | ||
604 | case snd_soc_dapm_post: | ||
605 | p->connect = 0; | ||
606 | break; | ||
607 | } | 529 | } |
608 | } | ||
609 | |||
610 | /* connect mux widget to its interconnecting audio paths */ | ||
611 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | ||
612 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
613 | struct snd_soc_dapm_path *path, const char *control_name, | ||
614 | const struct snd_kcontrol_new *kcontrol) | ||
615 | { | ||
616 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
617 | int i; | ||
618 | 530 | ||
619 | for (i = 0; i < e->max; i++) { | 531 | for (i = 0; i < e->items; i++) { |
620 | if (!(strcmp(control_name, e->texts[i]))) { | 532 | if (!(strcmp(control_name, e->texts[i]))) { |
621 | list_add(&path->list, &dapm->card->paths); | 533 | list_add(&path->list, &dapm->card->paths); |
622 | list_add(&path->list_sink, &dest->sources); | 534 | list_add(&path->list_sink, &dest->sources); |
623 | list_add(&path->list_source, &src->sinks); | 535 | list_add(&path->list_source, &src->sinks); |
624 | path->name = (char*)e->texts[i]; | 536 | path->name = (char*)e->texts[i]; |
625 | dapm_set_path_status(dest, path, 0); | 537 | if (i == item) |
538 | path->connect = 1; | ||
539 | else | ||
540 | path->connect = 0; | ||
626 | return 0; | 541 | return 0; |
627 | } | 542 | } |
628 | } | 543 | } |
@@ -630,6 +545,30 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
630 | return -ENODEV; | 545 | return -ENODEV; |
631 | } | 546 | } |
632 | 547 | ||
548 | /* set up initial codec paths */ | ||
549 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | ||
550 | struct snd_soc_dapm_path *p, int i) | ||
551 | { | ||
552 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | ||
553 | w->kcontrol_news[i].private_value; | ||
554 | unsigned int reg = mc->reg; | ||
555 | unsigned int shift = mc->shift; | ||
556 | unsigned int max = mc->max; | ||
557 | unsigned int mask = (1 << fls(max)) - 1; | ||
558 | unsigned int invert = mc->invert; | ||
559 | unsigned int val; | ||
560 | |||
561 | if (reg != SND_SOC_NOPM) { | ||
562 | soc_widget_read(w, reg, &val); | ||
563 | val = (val >> shift) & mask; | ||
564 | if (invert) | ||
565 | val = max - val; | ||
566 | p->connect = !!val; | ||
567 | } else { | ||
568 | p->connect = 0; | ||
569 | } | ||
570 | } | ||
571 | |||
633 | /* connect mixer widget to its interconnecting audio paths */ | 572 | /* connect mixer widget to its interconnecting audio paths */ |
634 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | 573 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, |
635 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 574 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
@@ -644,7 +583,7 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | |||
644 | list_add(&path->list_sink, &dest->sources); | 583 | list_add(&path->list_sink, &dest->sources); |
645 | list_add(&path->list_source, &src->sinks); | 584 | list_add(&path->list_source, &src->sinks); |
646 | path->name = dest->kcontrol_news[i].name; | 585 | path->name = dest->kcontrol_news[i].name; |
647 | dapm_set_path_status(dest, path, i); | 586 | dapm_set_mixer_path_status(dest, path, i); |
648 | return 0; | 587 | return 0; |
649 | } | 588 | } |
650 | } | 589 | } |
@@ -723,8 +662,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
723 | kcname_in_long_name = true; | 662 | kcname_in_long_name = true; |
724 | break; | 663 | break; |
725 | case snd_soc_dapm_mux: | 664 | case snd_soc_dapm_mux: |
726 | case snd_soc_dapm_virt_mux: | ||
727 | case snd_soc_dapm_value_mux: | ||
728 | wname_in_long_name = true; | 665 | wname_in_long_name = true; |
729 | kcname_in_long_name = false; | 666 | kcname_in_long_name = false; |
730 | break; | 667 | break; |
@@ -1218,7 +1155,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1218 | ret = regulator_allow_bypass(w->regulator, false); | 1155 | ret = regulator_allow_bypass(w->regulator, false); |
1219 | if (ret != 0) | 1156 | if (ret != 0) |
1220 | dev_warn(w->dapm->dev, | 1157 | dev_warn(w->dapm->dev, |
1221 | "ASoC: Failed to bypass %s: %d\n", | 1158 | "ASoC: Failed to unbypass %s: %d\n", |
1222 | w->name, ret); | 1159 | w->name, ret); |
1223 | } | 1160 | } |
1224 | 1161 | ||
@@ -1228,7 +1165,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1228 | ret = regulator_allow_bypass(w->regulator, true); | 1165 | ret = regulator_allow_bypass(w->regulator, true); |
1229 | if (ret != 0) | 1166 | if (ret != 0) |
1230 | dev_warn(w->dapm->dev, | 1167 | dev_warn(w->dapm->dev, |
1231 | "ASoC: Failed to unbypass %s: %d\n", | 1168 | "ASoC: Failed to bypass %s: %d\n", |
1232 | w->name, ret); | 1169 | w->name, ret); |
1233 | } | 1170 | } |
1234 | 1171 | ||
@@ -1823,6 +1760,8 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1823 | ASYNC_DOMAIN_EXCLUSIVE(async_domain); | 1760 | ASYNC_DOMAIN_EXCLUSIVE(async_domain); |
1824 | enum snd_soc_bias_level bias; | 1761 | enum snd_soc_bias_level bias; |
1825 | 1762 | ||
1763 | lockdep_assert_held(&card->dapm_mutex); | ||
1764 | |||
1826 | trace_snd_soc_dapm_start(card); | 1765 | trace_snd_soc_dapm_start(card); |
1827 | 1766 | ||
1828 | list_for_each_entry(d, &card->dapm_list, list) { | 1767 | list_for_each_entry(d, &card->dapm_list, list) { |
@@ -1897,10 +1836,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1897 | 1836 | ||
1898 | trace_snd_soc_dapm_walk_done(card); | 1837 | trace_snd_soc_dapm_walk_done(card); |
1899 | 1838 | ||
1900 | /* Run all the bias changes in parallel */ | 1839 | /* Run card bias changes at first */ |
1901 | list_for_each_entry(d, &card->dapm_list, list) | 1840 | dapm_pre_sequence_async(&card->dapm, 0); |
1902 | async_schedule_domain(dapm_pre_sequence_async, d, | 1841 | /* Run other bias changes in parallel */ |
1903 | &async_domain); | 1842 | list_for_each_entry(d, &card->dapm_list, list) { |
1843 | if (d != &card->dapm) | ||
1844 | async_schedule_domain(dapm_pre_sequence_async, d, | ||
1845 | &async_domain); | ||
1846 | } | ||
1904 | async_synchronize_full_domain(&async_domain); | 1847 | async_synchronize_full_domain(&async_domain); |
1905 | 1848 | ||
1906 | list_for_each_entry(w, &down_list, power_list) { | 1849 | list_for_each_entry(w, &down_list, power_list) { |
@@ -1920,10 +1863,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1920 | dapm_seq_run(card, &up_list, event, true); | 1863 | dapm_seq_run(card, &up_list, event, true); |
1921 | 1864 | ||
1922 | /* Run all the bias changes in parallel */ | 1865 | /* Run all the bias changes in parallel */ |
1923 | list_for_each_entry(d, &card->dapm_list, list) | 1866 | list_for_each_entry(d, &card->dapm_list, list) { |
1924 | async_schedule_domain(dapm_post_sequence_async, d, | 1867 | if (d != &card->dapm) |
1925 | &async_domain); | 1868 | async_schedule_domain(dapm_post_sequence_async, d, |
1869 | &async_domain); | ||
1870 | } | ||
1926 | async_synchronize_full_domain(&async_domain); | 1871 | async_synchronize_full_domain(&async_domain); |
1872 | /* Run card bias changes at last */ | ||
1873 | dapm_post_sequence_async(&card->dapm, 0); | ||
1927 | 1874 | ||
1928 | /* do we need to notify any clients that DAPM event is complete */ | 1875 | /* do we need to notify any clients that DAPM event is complete */ |
1929 | list_for_each_entry(d, &card->dapm_list, list) { | 1876 | list_for_each_entry(d, &card->dapm_list, list) { |
@@ -2110,6 +2057,8 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, | |||
2110 | struct snd_soc_dapm_path *path; | 2057 | struct snd_soc_dapm_path *path; |
2111 | int found = 0; | 2058 | int found = 0; |
2112 | 2059 | ||
2060 | lockdep_assert_held(&card->dapm_mutex); | ||
2061 | |||
2113 | /* find dapm widget path assoc with kcontrol */ | 2062 | /* find dapm widget path assoc with kcontrol */ |
2114 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2063 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2115 | if (!path->name || !e->texts[mux]) | 2064 | if (!path->name || !e->texts[mux]) |
@@ -2160,6 +2109,8 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, | |||
2160 | struct snd_soc_dapm_path *path; | 2109 | struct snd_soc_dapm_path *path; |
2161 | int found = 0; | 2110 | int found = 0; |
2162 | 2111 | ||
2112 | lockdep_assert_held(&card->dapm_mutex); | ||
2113 | |||
2163 | /* find dapm widget path assoc with kcontrol */ | 2114 | /* find dapm widget path assoc with kcontrol */ |
2164 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2115 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2165 | found = 1; | 2116 | found = 1; |
@@ -2325,6 +2276,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
2325 | { | 2276 | { |
2326 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); | 2277 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); |
2327 | 2278 | ||
2279 | dapm_assert_locked(dapm); | ||
2280 | |||
2328 | if (!w) { | 2281 | if (!w) { |
2329 | dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); | 2282 | dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); |
2330 | return -EINVAL; | 2283 | return -EINVAL; |
@@ -2341,18 +2294,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
2341 | } | 2294 | } |
2342 | 2295 | ||
2343 | /** | 2296 | /** |
2344 | * snd_soc_dapm_sync - scan and power dapm paths | 2297 | * snd_soc_dapm_sync_unlocked - scan and power dapm paths |
2345 | * @dapm: DAPM context | 2298 | * @dapm: DAPM context |
2346 | * | 2299 | * |
2347 | * Walks all dapm audio paths and powers widgets according to their | 2300 | * Walks all dapm audio paths and powers widgets according to their |
2348 | * stream or path usage. | 2301 | * stream or path usage. |
2349 | * | 2302 | * |
2303 | * Requires external locking. | ||
2304 | * | ||
2350 | * Returns 0 for success. | 2305 | * Returns 0 for success. |
2351 | */ | 2306 | */ |
2352 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | 2307 | int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm) |
2353 | { | 2308 | { |
2354 | int ret; | ||
2355 | |||
2356 | /* | 2309 | /* |
2357 | * Suppress early reports (eg, jacks syncing their state) to avoid | 2310 | * Suppress early reports (eg, jacks syncing their state) to avoid |
2358 | * silly DAPM runs during card startup. | 2311 | * silly DAPM runs during card startup. |
@@ -2360,8 +2313,25 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2360 | if (!dapm->card || !dapm->card->instantiated) | 2313 | if (!dapm->card || !dapm->card->instantiated) |
2361 | return 0; | 2314 | return 0; |
2362 | 2315 | ||
2316 | return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); | ||
2317 | } | ||
2318 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked); | ||
2319 | |||
2320 | /** | ||
2321 | * snd_soc_dapm_sync - scan and power dapm paths | ||
2322 | * @dapm: DAPM context | ||
2323 | * | ||
2324 | * Walks all dapm audio paths and powers widgets according to their | ||
2325 | * stream or path usage. | ||
2326 | * | ||
2327 | * Returns 0 for success. | ||
2328 | */ | ||
2329 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | ||
2330 | { | ||
2331 | int ret; | ||
2332 | |||
2363 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2333 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2364 | ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); | 2334 | ret = snd_soc_dapm_sync_unlocked(dapm); |
2365 | mutex_unlock(&dapm->card->dapm_mutex); | 2335 | mutex_unlock(&dapm->card->dapm_mutex); |
2366 | return ret; | 2336 | return ret; |
2367 | } | 2337 | } |
@@ -2444,8 +2414,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2444 | path->connect = 1; | 2414 | path->connect = 1; |
2445 | return 0; | 2415 | return 0; |
2446 | case snd_soc_dapm_mux: | 2416 | case snd_soc_dapm_mux: |
2447 | case snd_soc_dapm_virt_mux: | ||
2448 | case snd_soc_dapm_value_mux: | ||
2449 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, | 2417 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, |
2450 | &wsink->kcontrol_news[0]); | 2418 | &wsink->kcontrol_news[0]); |
2451 | if (ret != 0) | 2419 | if (ret != 0) |
@@ -2772,8 +2740,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
2772 | dapm_new_mixer(w); | 2740 | dapm_new_mixer(w); |
2773 | break; | 2741 | break; |
2774 | case snd_soc_dapm_mux: | 2742 | case snd_soc_dapm_mux: |
2775 | case snd_soc_dapm_virt_mux: | ||
2776 | case snd_soc_dapm_value_mux: | ||
2777 | dapm_new_mux(w); | 2743 | dapm_new_mux(w); |
2778 | break; | 2744 | break; |
2779 | case snd_soc_dapm_pga: | 2745 | case snd_soc_dapm_pga: |
@@ -2935,213 +2901,75 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2935 | { | 2901 | { |
2936 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2902 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2937 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2903 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2938 | unsigned int val; | 2904 | unsigned int reg_val, val; |
2939 | |||
2940 | val = snd_soc_read(codec, e->reg); | ||
2941 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; | ||
2942 | if (e->shift_l != e->shift_r) | ||
2943 | ucontrol->value.enumerated.item[1] = | ||
2944 | (val >> e->shift_r) & e->mask; | ||
2945 | |||
2946 | return 0; | ||
2947 | } | ||
2948 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | ||
2949 | |||
2950 | /** | ||
2951 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback | ||
2952 | * @kcontrol: mixer control | ||
2953 | * @ucontrol: control element information | ||
2954 | * | ||
2955 | * Callback to set the value of a dapm enumerated double mixer control. | ||
2956 | * | ||
2957 | * Returns 0 for success. | ||
2958 | */ | ||
2959 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | ||
2960 | struct snd_ctl_elem_value *ucontrol) | ||
2961 | { | ||
2962 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
2963 | struct snd_soc_card *card = codec->card; | ||
2964 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2965 | unsigned int val, mux, change; | ||
2966 | unsigned int mask; | ||
2967 | struct snd_soc_dapm_update update; | ||
2968 | int ret = 0; | ||
2969 | |||
2970 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | ||
2971 | return -EINVAL; | ||
2972 | mux = ucontrol->value.enumerated.item[0]; | ||
2973 | val = mux << e->shift_l; | ||
2974 | mask = e->mask << e->shift_l; | ||
2975 | if (e->shift_l != e->shift_r) { | ||
2976 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
2977 | return -EINVAL; | ||
2978 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
2979 | mask |= e->mask << e->shift_r; | ||
2980 | } | ||
2981 | |||
2982 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
2983 | |||
2984 | change = snd_soc_test_bits(codec, e->reg, mask, val); | ||
2985 | if (change) { | ||
2986 | update.kcontrol = kcontrol; | ||
2987 | update.reg = e->reg; | ||
2988 | update.mask = mask; | ||
2989 | update.val = val; | ||
2990 | card->update = &update; | ||
2991 | |||
2992 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | ||
2993 | |||
2994 | card->update = NULL; | ||
2995 | } | ||
2996 | |||
2997 | mutex_unlock(&card->dapm_mutex); | ||
2998 | 2905 | ||
2999 | if (ret > 0) | 2906 | if (e->reg != SND_SOC_NOPM) |
3000 | soc_dpcm_runtime_update(card); | 2907 | reg_val = snd_soc_read(codec, e->reg); |
3001 | 2908 | else | |
3002 | return change; | 2909 | reg_val = dapm_kcontrol_get_value(kcontrol); |
3003 | } | ||
3004 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | ||
3005 | |||
3006 | /** | ||
3007 | * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux | ||
3008 | * @kcontrol: mixer control | ||
3009 | * @ucontrol: control element information | ||
3010 | * | ||
3011 | * Returns 0 for success. | ||
3012 | */ | ||
3013 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | ||
3014 | struct snd_ctl_elem_value *ucontrol) | ||
3015 | { | ||
3016 | ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol); | ||
3017 | return 0; | ||
3018 | } | ||
3019 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | ||
3020 | |||
3021 | /** | ||
3022 | * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux | ||
3023 | * @kcontrol: mixer control | ||
3024 | * @ucontrol: control element information | ||
3025 | * | ||
3026 | * Returns 0 for success. | ||
3027 | */ | ||
3028 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | ||
3029 | struct snd_ctl_elem_value *ucontrol) | ||
3030 | { | ||
3031 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
3032 | struct snd_soc_card *card = codec->card; | ||
3033 | unsigned int value; | ||
3034 | struct soc_enum *e = | ||
3035 | (struct soc_enum *)kcontrol->private_value; | ||
3036 | int change; | ||
3037 | int ret = 0; | ||
3038 | |||
3039 | if (ucontrol->value.enumerated.item[0] >= e->max) | ||
3040 | return -EINVAL; | ||
3041 | |||
3042 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3043 | |||
3044 | value = ucontrol->value.enumerated.item[0]; | ||
3045 | change = dapm_kcontrol_set_value(kcontrol, value); | ||
3046 | if (change) | ||
3047 | ret = soc_dapm_mux_update_power(card, kcontrol, value, e); | ||
3048 | |||
3049 | mutex_unlock(&card->dapm_mutex); | ||
3050 | |||
3051 | if (ret > 0) | ||
3052 | soc_dpcm_runtime_update(card); | ||
3053 | |||
3054 | return change; | ||
3055 | } | ||
3056 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | ||
3057 | |||
3058 | /** | ||
3059 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | ||
3060 | * callback | ||
3061 | * @kcontrol: mixer control | ||
3062 | * @ucontrol: control element information | ||
3063 | * | ||
3064 | * Callback to get the value of a dapm semi enumerated double mixer control. | ||
3065 | * | ||
3066 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
3067 | * used for handling bitfield coded enumeration for example. | ||
3068 | * | ||
3069 | * Returns 0 for success. | ||
3070 | */ | ||
3071 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
3072 | struct snd_ctl_elem_value *ucontrol) | ||
3073 | { | ||
3074 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
3075 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
3076 | unsigned int reg_val, val, mux; | ||
3077 | 2910 | ||
3078 | reg_val = snd_soc_read(codec, e->reg); | ||
3079 | val = (reg_val >> e->shift_l) & e->mask; | 2911 | val = (reg_val >> e->shift_l) & e->mask; |
3080 | for (mux = 0; mux < e->max; mux++) { | 2912 | ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); |
3081 | if (val == e->values[mux]) | ||
3082 | break; | ||
3083 | } | ||
3084 | ucontrol->value.enumerated.item[0] = mux; | ||
3085 | if (e->shift_l != e->shift_r) { | 2913 | if (e->shift_l != e->shift_r) { |
3086 | val = (reg_val >> e->shift_r) & e->mask; | 2914 | val = (reg_val >> e->shift_r) & e->mask; |
3087 | for (mux = 0; mux < e->max; mux++) { | 2915 | val = snd_soc_enum_val_to_item(e, val); |
3088 | if (val == e->values[mux]) | 2916 | ucontrol->value.enumerated.item[1] = val; |
3089 | break; | ||
3090 | } | ||
3091 | ucontrol->value.enumerated.item[1] = mux; | ||
3092 | } | 2917 | } |
3093 | 2918 | ||
3094 | return 0; | 2919 | return 0; |
3095 | } | 2920 | } |
3096 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | 2921 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); |
3097 | 2922 | ||
3098 | /** | 2923 | /** |
3099 | * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set | 2924 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback |
3100 | * callback | ||
3101 | * @kcontrol: mixer control | 2925 | * @kcontrol: mixer control |
3102 | * @ucontrol: control element information | 2926 | * @ucontrol: control element information |
3103 | * | 2927 | * |
3104 | * Callback to set the value of a dapm semi enumerated double mixer control. | 2928 | * Callback to set the value of a dapm enumerated double mixer control. |
3105 | * | ||
3106 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
3107 | * used for handling bitfield coded enumeration for example. | ||
3108 | * | 2929 | * |
3109 | * Returns 0 for success. | 2930 | * Returns 0 for success. |
3110 | */ | 2931 | */ |
3111 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 2932 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
3112 | struct snd_ctl_elem_value *ucontrol) | 2933 | struct snd_ctl_elem_value *ucontrol) |
3113 | { | 2934 | { |
3114 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2935 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
3115 | struct snd_soc_card *card = codec->card; | 2936 | struct snd_soc_card *card = codec->card; |
3116 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2937 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
3117 | unsigned int val, mux, change; | 2938 | unsigned int *item = ucontrol->value.enumerated.item; |
2939 | unsigned int val, change; | ||
3118 | unsigned int mask; | 2940 | unsigned int mask; |
3119 | struct snd_soc_dapm_update update; | 2941 | struct snd_soc_dapm_update update; |
3120 | int ret = 0; | 2942 | int ret = 0; |
3121 | 2943 | ||
3122 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2944 | if (item[0] >= e->items) |
3123 | return -EINVAL; | 2945 | return -EINVAL; |
3124 | mux = ucontrol->value.enumerated.item[0]; | 2946 | |
3125 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | 2947 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; |
3126 | mask = e->mask << e->shift_l; | 2948 | mask = e->mask << e->shift_l; |
3127 | if (e->shift_l != e->shift_r) { | 2949 | if (e->shift_l != e->shift_r) { |
3128 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | 2950 | if (item[1] > e->items) |
3129 | return -EINVAL; | 2951 | return -EINVAL; |
3130 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | 2952 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l; |
3131 | mask |= e->mask << e->shift_r; | 2953 | mask |= e->mask << e->shift_r; |
3132 | } | 2954 | } |
3133 | 2955 | ||
3134 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2956 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
3135 | 2957 | ||
3136 | change = snd_soc_test_bits(codec, e->reg, mask, val); | 2958 | if (e->reg != SND_SOC_NOPM) |
2959 | change = snd_soc_test_bits(codec, e->reg, mask, val); | ||
2960 | else | ||
2961 | change = dapm_kcontrol_set_value(kcontrol, val); | ||
2962 | |||
3137 | if (change) { | 2963 | if (change) { |
3138 | update.kcontrol = kcontrol; | 2964 | if (e->reg != SND_SOC_NOPM) { |
3139 | update.reg = e->reg; | 2965 | update.kcontrol = kcontrol; |
3140 | update.mask = mask; | 2966 | update.reg = e->reg; |
3141 | update.val = val; | 2967 | update.mask = mask; |
3142 | card->update = &update; | 2968 | update.val = val; |
2969 | card->update = &update; | ||
2970 | } | ||
3143 | 2971 | ||
3144 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | 2972 | ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); |
3145 | 2973 | ||
3146 | card->update = NULL; | 2974 | card->update = NULL; |
3147 | } | 2975 | } |
@@ -3153,7 +2981,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
3153 | 2981 | ||
3154 | return change; | 2982 | return change; |
3155 | } | 2983 | } |
3156 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 2984 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
3157 | 2985 | ||
3158 | /** | 2986 | /** |
3159 | * snd_soc_dapm_info_pin_switch - Info for a pin switch | 2987 | * snd_soc_dapm_info_pin_switch - Info for a pin switch |
@@ -3210,15 +3038,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | |||
3210 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); | 3038 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
3211 | const char *pin = (const char *)kcontrol->private_value; | 3039 | const char *pin = (const char *)kcontrol->private_value; |
3212 | 3040 | ||
3213 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3214 | |||
3215 | if (ucontrol->value.integer.value[0]) | 3041 | if (ucontrol->value.integer.value[0]) |
3216 | snd_soc_dapm_enable_pin(&card->dapm, pin); | 3042 | snd_soc_dapm_enable_pin(&card->dapm, pin); |
3217 | else | 3043 | else |
3218 | snd_soc_dapm_disable_pin(&card->dapm, pin); | 3044 | snd_soc_dapm_disable_pin(&card->dapm, pin); |
3219 | 3045 | ||
3220 | mutex_unlock(&card->dapm_mutex); | ||
3221 | |||
3222 | snd_soc_dapm_sync(&card->dapm); | 3046 | snd_soc_dapm_sync(&card->dapm); |
3223 | return 0; | 3047 | return 0; |
3224 | } | 3048 | } |
@@ -3248,7 +3072,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3248 | ret = regulator_allow_bypass(w->regulator, true); | 3072 | ret = regulator_allow_bypass(w->regulator, true); |
3249 | if (ret != 0) | 3073 | if (ret != 0) |
3250 | dev_warn(w->dapm->dev, | 3074 | dev_warn(w->dapm->dev, |
3251 | "ASoC: Failed to unbypass %s: %d\n", | 3075 | "ASoC: Failed to bypass %s: %d\n", |
3252 | w->name, ret); | 3076 | w->name, ret); |
3253 | } | 3077 | } |
3254 | break; | 3078 | break; |
@@ -3287,8 +3111,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3287 | w->power_check = dapm_generic_check_power; | 3111 | w->power_check = dapm_generic_check_power; |
3288 | break; | 3112 | break; |
3289 | case snd_soc_dapm_mux: | 3113 | case snd_soc_dapm_mux: |
3290 | case snd_soc_dapm_virt_mux: | ||
3291 | case snd_soc_dapm_value_mux: | ||
3292 | w->power_check = dapm_generic_check_power; | 3114 | w->power_check = dapm_generic_check_power; |
3293 | break; | 3115 | break; |
3294 | case snd_soc_dapm_dai_out: | 3116 | case snd_soc_dapm_dai_out: |
@@ -3767,23 +3589,52 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | |||
3767 | } | 3589 | } |
3768 | 3590 | ||
3769 | /** | 3591 | /** |
3592 | * snd_soc_dapm_enable_pin_unlocked - enable pin. | ||
3593 | * @dapm: DAPM context | ||
3594 | * @pin: pin name | ||
3595 | * | ||
3596 | * Enables input/output pin and its parents or children widgets iff there is | ||
3597 | * a valid audio route and active audio stream. | ||
3598 | * | ||
3599 | * Requires external locking. | ||
3600 | * | ||
3601 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3602 | * do any widget power switching. | ||
3603 | */ | ||
3604 | int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, | ||
3605 | const char *pin) | ||
3606 | { | ||
3607 | return snd_soc_dapm_set_pin(dapm, pin, 1); | ||
3608 | } | ||
3609 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked); | ||
3610 | |||
3611 | /** | ||
3770 | * snd_soc_dapm_enable_pin - enable pin. | 3612 | * snd_soc_dapm_enable_pin - enable pin. |
3771 | * @dapm: DAPM context | 3613 | * @dapm: DAPM context |
3772 | * @pin: pin name | 3614 | * @pin: pin name |
3773 | * | 3615 | * |
3774 | * Enables input/output pin and its parents or children widgets iff there is | 3616 | * Enables input/output pin and its parents or children widgets iff there is |
3775 | * a valid audio route and active audio stream. | 3617 | * a valid audio route and active audio stream. |
3618 | * | ||
3776 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 3619 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
3777 | * do any widget power switching. | 3620 | * do any widget power switching. |
3778 | */ | 3621 | */ |
3779 | int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) | 3622 | int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) |
3780 | { | 3623 | { |
3781 | return snd_soc_dapm_set_pin(dapm, pin, 1); | 3624 | int ret; |
3625 | |||
3626 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3627 | |||
3628 | ret = snd_soc_dapm_set_pin(dapm, pin, 1); | ||
3629 | |||
3630 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3631 | |||
3632 | return ret; | ||
3782 | } | 3633 | } |
3783 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | 3634 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); |
3784 | 3635 | ||
3785 | /** | 3636 | /** |
3786 | * snd_soc_dapm_force_enable_pin - force a pin to be enabled | 3637 | * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled |
3787 | * @dapm: DAPM context | 3638 | * @dapm: DAPM context |
3788 | * @pin: pin name | 3639 | * @pin: pin name |
3789 | * | 3640 | * |
@@ -3791,11 +3642,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | |||
3791 | * intended for use with microphone bias supplies used in microphone | 3642 | * intended for use with microphone bias supplies used in microphone |
3792 | * jack detection. | 3643 | * jack detection. |
3793 | * | 3644 | * |
3645 | * Requires external locking. | ||
3646 | * | ||
3794 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 3647 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
3795 | * do any widget power switching. | 3648 | * do any widget power switching. |
3796 | */ | 3649 | */ |
3797 | int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | 3650 | int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, |
3798 | const char *pin) | 3651 | const char *pin) |
3799 | { | 3652 | { |
3800 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); | 3653 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); |
3801 | 3654 | ||
@@ -3811,25 +3664,103 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | |||
3811 | 3664 | ||
3812 | return 0; | 3665 | return 0; |
3813 | } | 3666 | } |
3667 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked); | ||
3668 | |||
3669 | /** | ||
3670 | * snd_soc_dapm_force_enable_pin - force a pin to be enabled | ||
3671 | * @dapm: DAPM context | ||
3672 | * @pin: pin name | ||
3673 | * | ||
3674 | * Enables input/output pin regardless of any other state. This is | ||
3675 | * intended for use with microphone bias supplies used in microphone | ||
3676 | * jack detection. | ||
3677 | * | ||
3678 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3679 | * do any widget power switching. | ||
3680 | */ | ||
3681 | int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | ||
3682 | const char *pin) | ||
3683 | { | ||
3684 | int ret; | ||
3685 | |||
3686 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3687 | |||
3688 | ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); | ||
3689 | |||
3690 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3691 | |||
3692 | return ret; | ||
3693 | } | ||
3814 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); | 3694 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); |
3815 | 3695 | ||
3816 | /** | 3696 | /** |
3697 | * snd_soc_dapm_disable_pin_unlocked - disable pin. | ||
3698 | * @dapm: DAPM context | ||
3699 | * @pin: pin name | ||
3700 | * | ||
3701 | * Disables input/output pin and its parents or children widgets. | ||
3702 | * | ||
3703 | * Requires external locking. | ||
3704 | * | ||
3705 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3706 | * do any widget power switching. | ||
3707 | */ | ||
3708 | int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, | ||
3709 | const char *pin) | ||
3710 | { | ||
3711 | return snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3712 | } | ||
3713 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked); | ||
3714 | |||
3715 | /** | ||
3817 | * snd_soc_dapm_disable_pin - disable pin. | 3716 | * snd_soc_dapm_disable_pin - disable pin. |
3818 | * @dapm: DAPM context | 3717 | * @dapm: DAPM context |
3819 | * @pin: pin name | 3718 | * @pin: pin name |
3820 | * | 3719 | * |
3821 | * Disables input/output pin and its parents or children widgets. | 3720 | * Disables input/output pin and its parents or children widgets. |
3721 | * | ||
3822 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 3722 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
3823 | * do any widget power switching. | 3723 | * do any widget power switching. |
3824 | */ | 3724 | */ |
3825 | int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, | 3725 | int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, |
3826 | const char *pin) | 3726 | const char *pin) |
3827 | { | 3727 | { |
3828 | return snd_soc_dapm_set_pin(dapm, pin, 0); | 3728 | int ret; |
3729 | |||
3730 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3731 | |||
3732 | ret = snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3733 | |||
3734 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3735 | |||
3736 | return ret; | ||
3829 | } | 3737 | } |
3830 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | 3738 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); |
3831 | 3739 | ||
3832 | /** | 3740 | /** |
3741 | * snd_soc_dapm_nc_pin_unlocked - permanently disable pin. | ||
3742 | * @dapm: DAPM context | ||
3743 | * @pin: pin name | ||
3744 | * | ||
3745 | * Marks the specified pin as being not connected, disabling it along | ||
3746 | * any parent or child widgets. At present this is identical to | ||
3747 | * snd_soc_dapm_disable_pin() but in future it will be extended to do | ||
3748 | * additional things such as disabling controls which only affect | ||
3749 | * paths through the pin. | ||
3750 | * | ||
3751 | * Requires external locking. | ||
3752 | * | ||
3753 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3754 | * do any widget power switching. | ||
3755 | */ | ||
3756 | int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, | ||
3757 | const char *pin) | ||
3758 | { | ||
3759 | return snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3760 | } | ||
3761 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked); | ||
3762 | |||
3763 | /** | ||
3833 | * snd_soc_dapm_nc_pin - permanently disable pin. | 3764 | * snd_soc_dapm_nc_pin - permanently disable pin. |
3834 | * @dapm: DAPM context | 3765 | * @dapm: DAPM context |
3835 | * @pin: pin name | 3766 | * @pin: pin name |
@@ -3845,7 +3776,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | |||
3845 | */ | 3776 | */ |
3846 | int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) | 3777 | int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) |
3847 | { | 3778 | { |
3848 | return snd_soc_dapm_set_pin(dapm, pin, 0); | 3779 | int ret; |
3780 | |||
3781 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3782 | |||
3783 | ret = snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3784 | |||
3785 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3786 | |||
3787 | return ret; | ||
3849 | } | 3788 | } |
3850 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); | 3789 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); |
3851 | 3790 | ||
@@ -3985,7 +3924,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) | |||
3985 | } | 3924 | } |
3986 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | 3925 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
3987 | 3926 | ||
3988 | static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | 3927 | static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) |
3989 | { | 3928 | { |
3990 | struct snd_soc_card *card = dapm->card; | 3929 | struct snd_soc_card *card = dapm->card; |
3991 | struct snd_soc_dapm_widget *w; | 3930 | struct snd_soc_dapm_widget *w; |
@@ -4025,14 +3964,21 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
4025 | */ | 3964 | */ |
4026 | void snd_soc_dapm_shutdown(struct snd_soc_card *card) | 3965 | void snd_soc_dapm_shutdown(struct snd_soc_card *card) |
4027 | { | 3966 | { |
4028 | struct snd_soc_codec *codec; | 3967 | struct snd_soc_dapm_context *dapm; |
4029 | 3968 | ||
4030 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | 3969 | list_for_each_entry(dapm, &card->dapm_list, list) { |
4031 | soc_dapm_shutdown_codec(&codec->dapm); | 3970 | if (dapm != &card->dapm) { |
4032 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | 3971 | soc_dapm_shutdown_dapm(dapm); |
4033 | snd_soc_dapm_set_bias_level(&codec->dapm, | 3972 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) |
4034 | SND_SOC_BIAS_OFF); | 3973 | snd_soc_dapm_set_bias_level(dapm, |
3974 | SND_SOC_BIAS_OFF); | ||
3975 | } | ||
4035 | } | 3976 | } |
3977 | |||
3978 | soc_dapm_shutdown_dapm(&card->dapm); | ||
3979 | if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) | ||
3980 | snd_soc_dapm_set_bias_level(&card->dapm, | ||
3981 | SND_SOC_BIAS_OFF); | ||
4036 | } | 3982 | } |
4037 | 3983 | ||
4038 | /* Module information */ | 3984 | /* Module information */ |