diff options
| -rw-r--r-- | include/sound/soc-dapm.h | 5 | ||||
| -rw-r--r-- | sound/soc/soc-dapm.c | 112 |
2 files changed, 102 insertions, 15 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 70216d20e897..96c5e0ec81d1 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
| @@ -107,6 +107,10 @@ struct device; | |||
| 107 | { .id = snd_soc_dapm_mux, .name = wname, \ | 107 | { .id = snd_soc_dapm_mux, .name = wname, \ |
| 108 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ | 108 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
| 109 | .kcontrol_news = wcontrols, .num_kcontrols = 1} | 109 | .kcontrol_news = wcontrols, .num_kcontrols = 1} |
| 110 | #define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \ | ||
| 111 | { .id = snd_soc_dapm_demux, .name = wname, \ | ||
| 112 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ | ||
| 113 | .kcontrol_news = wcontrols, .num_kcontrols = 1} | ||
| 110 | 114 | ||
| 111 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ | 115 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ |
| 112 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ | 116 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ |
| @@ -452,6 +456,7 @@ enum snd_soc_dapm_type { | |||
| 452 | snd_soc_dapm_input = 0, /* input pin */ | 456 | snd_soc_dapm_input = 0, /* input pin */ |
| 453 | snd_soc_dapm_output, /* output pin */ | 457 | snd_soc_dapm_output, /* output pin */ |
| 454 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ | 458 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ |
| 459 | snd_soc_dapm_demux, /* connects the input to one of multiple outputs */ | ||
| 455 | snd_soc_dapm_mixer, /* mixes several analog signals together */ | 460 | snd_soc_dapm_mixer, /* mixes several analog signals together */ |
| 456 | snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */ | 461 | snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */ |
| 457 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ | 462 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5c159f4f8097..a2e5f2278caa 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
| @@ -70,6 +70,7 @@ 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_demux] = 6, | ||
| 73 | [snd_soc_dapm_dac] = 7, | 74 | [snd_soc_dapm_dac] = 7, |
| 74 | [snd_soc_dapm_switch] = 8, | 75 | [snd_soc_dapm_switch] = 8, |
| 75 | [snd_soc_dapm_mixer] = 8, | 76 | [snd_soc_dapm_mixer] = 8, |
| @@ -100,6 +101,7 @@ static int dapm_down_seq[] = { | |||
| 100 | [snd_soc_dapm_mic] = 7, | 101 | [snd_soc_dapm_mic] = 7, |
| 101 | [snd_soc_dapm_micbias] = 8, | 102 | [snd_soc_dapm_micbias] = 8, |
| 102 | [snd_soc_dapm_mux] = 9, | 103 | [snd_soc_dapm_mux] = 9, |
| 104 | [snd_soc_dapm_demux] = 9, | ||
| 103 | [snd_soc_dapm_aif_in] = 10, | 105 | [snd_soc_dapm_aif_in] = 10, |
| 104 | [snd_soc_dapm_aif_out] = 10, | 106 | [snd_soc_dapm_aif_out] = 10, |
| 105 | [snd_soc_dapm_dai_in] = 10, | 107 | [snd_soc_dapm_dai_in] = 10, |
| @@ -356,6 +358,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, | |||
| 356 | } | 358 | } |
| 357 | } | 359 | } |
| 358 | break; | 360 | break; |
| 361 | case snd_soc_dapm_demux: | ||
| 359 | case snd_soc_dapm_mux: | 362 | case snd_soc_dapm_mux: |
| 360 | e = (struct soc_enum *)kcontrol->private_value; | 363 | e = (struct soc_enum *)kcontrol->private_value; |
| 361 | 364 | ||
| @@ -639,9 +642,10 @@ out: | |||
| 639 | 642 | ||
| 640 | /* connect mux widget to its interconnecting audio paths */ | 643 | /* connect mux widget to its interconnecting audio paths */ |
| 641 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | 644 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
| 642 | struct snd_soc_dapm_path *path, const char *control_name) | 645 | struct snd_soc_dapm_path *path, const char *control_name, |
| 646 | struct snd_soc_dapm_widget *w) | ||
| 643 | { | 647 | { |
| 644 | const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0]; | 648 | const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0]; |
| 645 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 649 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 646 | unsigned int val, item; | 650 | unsigned int val, item; |
| 647 | int i; | 651 | int i; |
| @@ -781,6 +785,7 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
| 781 | wname_in_long_name = false; | 785 | wname_in_long_name = false; |
| 782 | kcname_in_long_name = true; | 786 | kcname_in_long_name = true; |
| 783 | break; | 787 | break; |
| 788 | case snd_soc_dapm_demux: | ||
| 784 | case snd_soc_dapm_mux: | 789 | case snd_soc_dapm_mux: |
| 785 | wname_in_long_name = true; | 790 | wname_in_long_name = true; |
| 786 | kcname_in_long_name = false; | 791 | kcname_in_long_name = false; |
| @@ -886,17 +891,32 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
| 886 | { | 891 | { |
| 887 | struct snd_soc_dapm_context *dapm = w->dapm; | 892 | struct snd_soc_dapm_context *dapm = w->dapm; |
| 888 | struct snd_soc_dapm_path *path; | 893 | struct snd_soc_dapm_path *path; |
| 894 | struct list_head *paths; | ||
| 895 | const char *type; | ||
| 889 | int ret; | 896 | int ret; |
| 890 | 897 | ||
| 898 | switch (w->id) { | ||
| 899 | case snd_soc_dapm_mux: | ||
| 900 | paths = &w->sources; | ||
| 901 | type = "mux"; | ||
| 902 | break; | ||
| 903 | case snd_soc_dapm_demux: | ||
| 904 | paths = &w->sinks; | ||
| 905 | type = "demux"; | ||
| 906 | break; | ||
| 907 | default: | ||
| 908 | return -EINVAL; | ||
| 909 | } | ||
| 910 | |||
| 891 | if (w->num_kcontrols != 1) { | 911 | if (w->num_kcontrols != 1) { |
| 892 | dev_err(dapm->dev, | 912 | dev_err(dapm->dev, |
| 893 | "ASoC: mux %s has incorrect number of controls\n", | 913 | "ASoC: %s %s has incorrect number of controls\n", type, |
| 894 | w->name); | 914 | w->name); |
| 895 | return -EINVAL; | 915 | return -EINVAL; |
| 896 | } | 916 | } |
| 897 | 917 | ||
| 898 | if (list_empty(&w->sources)) { | 918 | if (list_empty(paths)) { |
| 899 | dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name); | 919 | dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name); |
| 900 | return -EINVAL; | 920 | return -EINVAL; |
| 901 | } | 921 | } |
| 902 | 922 | ||
| @@ -904,9 +924,16 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
| 904 | if (ret < 0) | 924 | if (ret < 0) |
| 905 | return ret; | 925 | return ret; |
| 906 | 926 | ||
| 907 | list_for_each_entry(path, &w->sources, list_sink) { | 927 | if (w->id == snd_soc_dapm_mux) { |
| 908 | if (path->name) | 928 | list_for_each_entry(path, &w->sources, list_sink) { |
| 909 | dapm_kcontrol_add_path(w->kcontrols[0], path); | 929 | if (path->name) |
| 930 | dapm_kcontrol_add_path(w->kcontrols[0], path); | ||
| 931 | } | ||
| 932 | } else { | ||
| 933 | list_for_each_entry(path, &w->sinks, list_source) { | ||
| 934 | if (path->name) | ||
| 935 | dapm_kcontrol_add_path(w->kcontrols[0], path); | ||
| 936 | } | ||
| 910 | } | 937 | } |
| 911 | 938 | ||
| 912 | return 0; | 939 | return 0; |
| @@ -2414,6 +2441,50 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) | |||
| 2414 | } | 2441 | } |
| 2415 | } | 2442 | } |
| 2416 | 2443 | ||
| 2444 | static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm, | ||
| 2445 | struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink, | ||
| 2446 | const char *control) | ||
| 2447 | { | ||
| 2448 | bool dynamic_source = false; | ||
| 2449 | bool dynamic_sink = false; | ||
| 2450 | |||
| 2451 | if (!control) | ||
| 2452 | return 0; | ||
| 2453 | |||
| 2454 | switch (source->id) { | ||
| 2455 | case snd_soc_dapm_demux: | ||
| 2456 | dynamic_source = true; | ||
| 2457 | break; | ||
| 2458 | default: | ||
| 2459 | break; | ||
| 2460 | } | ||
| 2461 | |||
| 2462 | switch (sink->id) { | ||
| 2463 | case snd_soc_dapm_mux: | ||
| 2464 | case snd_soc_dapm_switch: | ||
| 2465 | case snd_soc_dapm_mixer: | ||
| 2466 | case snd_soc_dapm_mixer_named_ctl: | ||
| 2467 | dynamic_sink = true; | ||
| 2468 | break; | ||
| 2469 | default: | ||
| 2470 | break; | ||
| 2471 | } | ||
| 2472 | |||
| 2473 | if (dynamic_source && dynamic_sink) { | ||
| 2474 | dev_err(dapm->dev, | ||
| 2475 | "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n", | ||
| 2476 | source->name, control, sink->name); | ||
| 2477 | return -EINVAL; | ||
| 2478 | } else if (!dynamic_source && !dynamic_sink) { | ||
| 2479 | dev_err(dapm->dev, | ||
| 2480 | "Control not supported for path %s -> [%s] -> %s\n", | ||
| 2481 | source->name, control, sink->name); | ||
| 2482 | return -EINVAL; | ||
| 2483 | } | ||
| 2484 | |||
| 2485 | return 0; | ||
| 2486 | } | ||
| 2487 | |||
| 2417 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | 2488 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
| 2418 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, | 2489 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
| 2419 | const char *control, | 2490 | const char *control, |
| @@ -2444,6 +2515,10 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
| 2444 | return -EINVAL; | 2515 | return -EINVAL; |
| 2445 | } | 2516 | } |
| 2446 | 2517 | ||
| 2518 | ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control); | ||
| 2519 | if (ret) | ||
| 2520 | return ret; | ||
| 2521 | |||
| 2447 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2522 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
| 2448 | if (!path) | 2523 | if (!path) |
| 2449 | return -ENOMEM; | 2524 | return -ENOMEM; |
| @@ -2463,10 +2538,19 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
| 2463 | if (control == NULL) { | 2538 | if (control == NULL) { |
| 2464 | path->connect = 1; | 2539 | path->connect = 1; |
| 2465 | } else { | 2540 | } else { |
| 2466 | /* connect dynamic paths */ | 2541 | switch (wsource->id) { |
| 2542 | case snd_soc_dapm_demux: | ||
| 2543 | ret = dapm_connect_mux(dapm, path, control, wsource); | ||
| 2544 | if (ret) | ||
| 2545 | goto err; | ||
| 2546 | break; | ||
| 2547 | default: | ||
| 2548 | break; | ||
| 2549 | } | ||
| 2550 | |||
| 2467 | switch (wsink->id) { | 2551 | switch (wsink->id) { |
| 2468 | case snd_soc_dapm_mux: | 2552 | case snd_soc_dapm_mux: |
| 2469 | ret = dapm_connect_mux(dapm, path, control); | 2553 | ret = dapm_connect_mux(dapm, path, control, wsink); |
| 2470 | if (ret != 0) | 2554 | if (ret != 0) |
| 2471 | goto err; | 2555 | goto err; |
| 2472 | break; | 2556 | break; |
| @@ -2478,11 +2562,7 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
| 2478 | goto err; | 2562 | goto err; |
| 2479 | break; | 2563 | break; |
| 2480 | default: | 2564 | default: |
| 2481 | dev_err(dapm->dev, | 2565 | break; |
| 2482 | "Control not supported for path %s -> [%s] -> %s\n", | ||
| 2483 | wsource->name, control, wsink->name); | ||
| 2484 | ret = -EINVAL; | ||
| 2485 | goto err; | ||
| 2486 | } | 2566 | } |
| 2487 | } | 2567 | } |
| 2488 | 2568 | ||
| @@ -2815,6 +2895,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
| 2815 | dapm_new_mixer(w); | 2895 | dapm_new_mixer(w); |
| 2816 | break; | 2896 | break; |
| 2817 | case snd_soc_dapm_mux: | 2897 | case snd_soc_dapm_mux: |
| 2898 | case snd_soc_dapm_demux: | ||
| 2818 | dapm_new_mux(w); | 2899 | dapm_new_mux(w); |
| 2819 | break; | 2900 | break; |
| 2820 | case snd_soc_dapm_pga: | 2901 | case snd_soc_dapm_pga: |
| @@ -3219,6 +3300,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
| 3219 | w->power_check = dapm_always_on_check_power; | 3300 | w->power_check = dapm_always_on_check_power; |
| 3220 | break; | 3301 | break; |
| 3221 | case snd_soc_dapm_mux: | 3302 | case snd_soc_dapm_mux: |
| 3303 | case snd_soc_dapm_demux: | ||
| 3222 | case snd_soc_dapm_switch: | 3304 | case snd_soc_dapm_switch: |
| 3223 | case snd_soc_dapm_mixer: | 3305 | case snd_soc_dapm_mixer: |
| 3224 | case snd_soc_dapm_mixer_named_ctl: | 3306 | case snd_soc_dapm_mixer_named_ctl: |
