aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h5
-rw-r--r--sound/soc/soc-dapm.c112
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 */
641static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, 644static 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
2444static 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
2417static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, 2488static 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: