aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-16 22:37:51 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-17 11:10:10 -0500
commit888df395ebc5c88cde45478660197ca46665efe2 (patch)
treea0481614ac6ccfa246bf043fe953ab28f7c582e8
parent3056557f3b2387d4ac99ca8af14956cd2bf003c2 (diff)
ASoC: dapm: Implement and instantiate DAI widgets
In order to allow us to do smarter things with DAI links create DAPM widgets which directly represent the DAIs in the DAPM graph. These are automatically created from the DAIs as we probe the card with references held in both directions between the widget and the DAI. The widgets are not made available for direct instantiation by drivers, they are created automatically from the DAIs. Drivers should be updated to create stream routes using DAPM maps rather than by annotating AIF and DAC widgets with streams. In order to ease transition to this model from existing drivers we automatically create DAPM routes between the DAI widgets and the existing stream widgets which are started and stopped by the DAI widgets, though the old stream handling mechanism is still in place. This also has the nice effect of removing non-DAPM devices as any device with a DAI acquires a widget automatically which will allow future simplifications to the core DAPM logic. The intention is that in future the AIF and DAI widgets will gain the ability to interact such that we are able to manage activity on individual channels independantly rather than powering up and down the entire AIF as we do currently. Currently we only generate these for CODECs, mostly as I have no systems with non-CODEC DAPM to integrate with. It should be a simple matter of programming to add the additional hookup for these. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@ti.com>
-rw-r--r--include/sound/soc-dai.h4
-rw-r--r--include/sound/soc-dapm.h4
-rw-r--r--sound/soc/soc-core.c11
-rw-r--r--sound/soc/soc-dapm.c135
4 files changed, 146 insertions, 8 deletions
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 2413acc54883..adb07fcd712c 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -17,6 +17,7 @@
17#include <linux/list.h> 17#include <linux/list.h>
18 18
19struct snd_pcm_substream; 19struct snd_pcm_substream;
20struct snd_soc_dapm_widget;
20 21
21/* 22/*
22 * DAI hardware audio formats. 23 * DAI hardware audio formats.
@@ -238,6 +239,9 @@ struct snd_soc_dai {
238 unsigned char pop_wait:1; 239 unsigned char pop_wait:1;
239 unsigned char probed:1; 240 unsigned char probed:1;
240 241
242 struct snd_soc_dapm_widget *playback_widget;
243 struct snd_soc_dapm_widget *capture_widget;
244
241 /* DAI DMA data */ 245 /* DAI DMA data */
242 void *playback_dma_data; 246 void *playback_dma_data;
243 void *capture_dma_data; 247 void *capture_dma_data;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 91eb8126c00e..e46107fffeb4 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -355,6 +355,9 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
355int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, 355int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
356 const struct snd_soc_dapm_widget *widget, 356 const struct snd_soc_dapm_widget *widget,
357 int num); 357 int num);
358int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
359 struct snd_soc_dai *dai);
360int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
358 361
359/* dapm path setup */ 362/* dapm path setup */
360int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm); 363int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
@@ -425,6 +428,7 @@ enum snd_soc_dapm_type {
425 snd_soc_dapm_aif_in, /* audio interface input */ 428 snd_soc_dapm_aif_in, /* audio interface input */
426 snd_soc_dapm_aif_out, /* audio interface output */ 429 snd_soc_dapm_aif_out, /* audio interface output */
427 snd_soc_dapm_siggen, /* signal generator */ 430 snd_soc_dapm_siggen, /* signal generator */
431 snd_soc_dapm_dai, /* link to DAI structure */
428}; 432};
429 433
430/* 434/*
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 77d230cba61a..32ca75e20024 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1010,6 +1010,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
1010{ 1010{
1011 int ret = 0; 1011 int ret = 0;
1012 const struct snd_soc_codec_driver *driver = codec->driver; 1012 const struct snd_soc_codec_driver *driver = codec->driver;
1013 struct snd_soc_dai *dai;
1013 1014
1014 codec->card = card; 1015 codec->card = card;
1015 codec->dapm.card = card; 1016 codec->dapm.card = card;
@@ -1024,6 +1025,14 @@ static int soc_probe_codec(struct snd_soc_card *card,
1024 snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, 1025 snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
1025 driver->num_dapm_widgets); 1026 driver->num_dapm_widgets);
1026 1027
1028 /* Create DAPM widgets for each DAI stream */
1029 list_for_each_entry(dai, &dai_list, list) {
1030 if (dai->dev != codec->dev)
1031 continue;
1032
1033 snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
1034 }
1035
1027 codec->dapm.idle_bias_off = driver->idle_bias_off; 1036 codec->dapm.idle_bias_off = driver->idle_bias_off;
1028 1037
1029 if (driver->probe) { 1038 if (driver->probe) {
@@ -1500,6 +1509,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
1500 } 1509 }
1501 } 1510 }
1502 1511
1512 snd_soc_dapm_link_dai_widgets(card);
1513
1503 if (card->controls) 1514 if (card->controls)
1504 snd_soc_add_card_controls(card, card->controls, card->num_controls); 1515 snd_soc_add_card_controls(card, card->controls, card->num_controls);
1505 1516
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 97915eb711cc..a4707d0fdf3d 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -52,6 +52,7 @@ static int dapm_up_seq[] = {
52 [snd_soc_dapm_supply] = 1, 52 [snd_soc_dapm_supply] = 1,
53 [snd_soc_dapm_regulator_supply] = 1, 53 [snd_soc_dapm_regulator_supply] = 1,
54 [snd_soc_dapm_micbias] = 2, 54 [snd_soc_dapm_micbias] = 2,
55 [snd_soc_dapm_dai] = 3,
55 [snd_soc_dapm_aif_in] = 3, 56 [snd_soc_dapm_aif_in] = 3,
56 [snd_soc_dapm_aif_out] = 3, 57 [snd_soc_dapm_aif_out] = 3,
57 [snd_soc_dapm_mic] = 4, 58 [snd_soc_dapm_mic] = 4,
@@ -86,6 +87,7 @@ static int dapm_down_seq[] = {
86 [snd_soc_dapm_value_mux] = 9, 87 [snd_soc_dapm_value_mux] = 9,
87 [snd_soc_dapm_aif_in] = 10, 88 [snd_soc_dapm_aif_in] = 10,
88 [snd_soc_dapm_aif_out] = 10, 89 [snd_soc_dapm_aif_out] = 10,
90 [snd_soc_dapm_dai] = 10,
89 [snd_soc_dapm_regulator_supply] = 11, 91 [snd_soc_dapm_regulator_supply] = 11,
90 [snd_soc_dapm_supply] = 11, 92 [snd_soc_dapm_supply] = 11,
91 [snd_soc_dapm_post] = 12, 93 [snd_soc_dapm_post] = 12,
@@ -365,6 +367,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
365 case snd_soc_dapm_regulator_supply: 367 case snd_soc_dapm_regulator_supply:
366 case snd_soc_dapm_aif_in: 368 case snd_soc_dapm_aif_in:
367 case snd_soc_dapm_aif_out: 369 case snd_soc_dapm_aif_out:
370 case snd_soc_dapm_dai:
368 case snd_soc_dapm_hp: 371 case snd_soc_dapm_hp:
369 case snd_soc_dapm_mic: 372 case snd_soc_dapm_mic:
370 case snd_soc_dapm_spk: 373 case snd_soc_dapm_spk:
@@ -522,17 +525,17 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
522 * for widgets so cut the prefix off 525 * for widgets so cut the prefix off
523 * the front of the widget name. 526 * the front of the widget name.
524 */ 527 */
525 snprintf(path->long_name, name_len, "%s %s", 528 snprintf((char *)path->long_name, name_len,
526 w->name + prefix_len, 529 "%s %s", w->name + prefix_len,
527 w->kcontrol_news[i].name); 530 w->kcontrol_news[i].name);
528 break; 531 break;
529 case snd_soc_dapm_mixer_named_ctl: 532 case snd_soc_dapm_mixer_named_ctl:
530 snprintf(path->long_name, name_len, "%s", 533 snprintf((char *)path->long_name, name_len,
531 w->kcontrol_news[i].name); 534 "%s", w->kcontrol_news[i].name);
532 break; 535 break;
533 } 536 }
534 537
535 path->long_name[name_len - 1] = '\0'; 538 ((char *)path->long_name)[name_len - 1] = '\0';
536 539
537 path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], 540 path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
538 wlist, path->long_name, 541 wlist, path->long_name,
@@ -566,7 +569,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
566 struct snd_soc_dapm_widget_list *wlist; 569 struct snd_soc_dapm_widget_list *wlist;
567 int shared, wlistentries; 570 int shared, wlistentries;
568 size_t wlistsize; 571 size_t wlistsize;
569 char *name; 572 const char *name;
570 573
571 if (w->num_kcontrols != 1) { 574 if (w->num_kcontrols != 1) {
572 dev_err(dapm->dev, 575 dev_err(dapm->dev,
@@ -702,6 +705,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
702 switch (widget->id) { 705 switch (widget->id) {
703 case snd_soc_dapm_adc: 706 case snd_soc_dapm_adc:
704 case snd_soc_dapm_aif_out: 707 case snd_soc_dapm_aif_out:
708 case snd_soc_dapm_dai:
705 if (widget->active) { 709 if (widget->active) {
706 widget->outputs = snd_soc_dapm_suspend_check(widget); 710 widget->outputs = snd_soc_dapm_suspend_check(widget);
707 return widget->outputs; 711 return widget->outputs;
@@ -773,6 +777,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
773 switch (widget->id) { 777 switch (widget->id) {
774 case snd_soc_dapm_dac: 778 case snd_soc_dapm_dac:
775 case snd_soc_dapm_aif_in: 779 case snd_soc_dapm_aif_in:
780 case snd_soc_dapm_dai:
776 if (widget->active) { 781 if (widget->active) {
777 widget->inputs = snd_soc_dapm_suspend_check(widget); 782 widget->inputs = snd_soc_dapm_suspend_check(widget);
778 return widget->inputs; 783 return widget->inputs;
@@ -892,6 +897,13 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
892 return out != 0 && in != 0; 897 return out != 0 && in != 0;
893} 898}
894 899
900static int dapm_dai_check_power(struct snd_soc_dapm_widget *w)
901{
902 DAPM_UPDATE_STAT(w, power_checks);
903
904 return w->active;
905}
906
895/* Check to see if an ADC has power */ 907/* Check to see if an ADC has power */
896static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) 908static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
897{ 909{
@@ -2049,6 +2061,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
2049 case snd_soc_dapm_regulator_supply: 2061 case snd_soc_dapm_regulator_supply:
2050 case snd_soc_dapm_aif_in: 2062 case snd_soc_dapm_aif_in:
2051 case snd_soc_dapm_aif_out: 2063 case snd_soc_dapm_aif_out:
2064 case snd_soc_dapm_dai:
2052 list_add(&path->list, &dapm->card->paths); 2065 list_add(&path->list, &dapm->card->paths);
2053 list_add(&path->list_sink, &wsink->sources); 2066 list_add(&path->list_sink, &wsink->sources);
2054 list_add(&path->list_source, &wsource->sinks); 2067 list_add(&path->list_source, &wsource->sinks);
@@ -2732,10 +2745,10 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
2732 return NULL; 2745 return NULL;
2733 } 2746 }
2734 if (dapm->codec && dapm->codec->name_prefix) 2747 if (dapm->codec && dapm->codec->name_prefix)
2735 snprintf(w->name, name_len, "%s %s", 2748 snprintf((char *)w->name, name_len, "%s %s",
2736 dapm->codec->name_prefix, widget->name); 2749 dapm->codec->name_prefix, widget->name);
2737 else 2750 else
2738 snprintf(w->name, name_len, "%s", widget->name); 2751 snprintf((char *)w->name, name_len, "%s", widget->name);
2739 2752
2740 switch (w->id) { 2753 switch (w->id) {
2741 case snd_soc_dapm_switch: 2754 case snd_soc_dapm_switch:
@@ -2771,6 +2784,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
2771 case snd_soc_dapm_regulator_supply: 2784 case snd_soc_dapm_regulator_supply:
2772 w->power_check = dapm_supply_check_power; 2785 w->power_check = dapm_supply_check_power;
2773 break; 2786 break;
2787 case snd_soc_dapm_dai:
2788 w->power_check = dapm_dai_check_power;
2789 break;
2774 default: 2790 default:
2775 w->power_check = dapm_always_on_check_power; 2791 w->power_check = dapm_always_on_check_power;
2776 break; 2792 break;
@@ -2822,6 +2838,109 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
2822} 2838}
2823EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); 2839EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
2824 2840
2841int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
2842 struct snd_soc_dai *dai)
2843{
2844 struct snd_soc_dapm_widget template;
2845 struct snd_soc_dapm_widget *w;
2846
2847 WARN_ON(dapm->dev != dai->dev);
2848
2849 memset(&template, 0, sizeof(template));
2850 template.reg = SND_SOC_NOPM;
2851
2852 if (dai->driver->playback.stream_name) {
2853 template.id = snd_soc_dapm_dai;
2854 template.name = dai->driver->playback.stream_name;
2855 template.sname = dai->driver->playback.stream_name;
2856
2857 dev_dbg(dai->dev, "adding %s widget\n",
2858 template.name);
2859
2860 w = snd_soc_dapm_new_control(dapm, &template);
2861 if (!w) {
2862 dev_err(dapm->dev, "Failed to create %s widget\n",
2863 dai->driver->playback.stream_name);
2864 }
2865
2866 w->priv = dai;
2867 dai->playback_widget = w;
2868 }
2869
2870 if (dai->driver->capture.stream_name) {
2871 template.id = snd_soc_dapm_dai;
2872 template.name = dai->driver->capture.stream_name;
2873 template.sname = dai->driver->capture.stream_name;
2874
2875 dev_dbg(dai->dev, "adding %s widget\n",
2876 template.name);
2877
2878 w = snd_soc_dapm_new_control(dapm, &template);
2879 if (!w) {
2880 dev_err(dapm->dev, "Failed to create %s widget\n",
2881 dai->driver->capture.stream_name);
2882 }
2883
2884 w->priv = dai;
2885 dai->capture_widget = w;
2886 }
2887
2888 return 0;
2889}
2890
2891int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
2892{
2893 struct snd_soc_dapm_widget *dai_w, *w;
2894 struct snd_soc_dai *dai;
2895 struct snd_soc_dapm_route r;
2896
2897 memset(&r, 0, sizeof(r));
2898
2899 /* For each DAI widget... */
2900 list_for_each_entry(dai_w, &card->widgets, list) {
2901 if (dai_w->id != snd_soc_dapm_dai)
2902 continue;
2903
2904 dai = dai_w->priv;
2905
2906 /* ...find all widgets with the same stream and link them */
2907 list_for_each_entry(w, &card->widgets, list) {
2908 if (w->dapm != dai_w->dapm)
2909 continue;
2910
2911 if (w->id == snd_soc_dapm_dai)
2912 continue;
2913
2914 if (!w->sname)
2915 continue;
2916
2917 if (dai->driver->playback.stream_name &&
2918 strstr(w->sname,
2919 dai->driver->playback.stream_name)) {
2920 r.source = dai->playback_widget->name;
2921 r.sink = w->name;
2922 dev_dbg(dai->dev, "%s -> %s\n",
2923 r.source, r.sink);
2924
2925 snd_soc_dapm_add_route(w->dapm, &r);
2926 }
2927
2928 if (dai->driver->capture.stream_name &&
2929 strstr(w->sname,
2930 dai->driver->capture.stream_name)) {
2931 r.source = w->name;
2932 r.sink = dai->capture_widget->name;
2933 dev_dbg(dai->dev, "%s -> %s\n",
2934 r.source, r.sink);
2935
2936 snd_soc_dapm_add_route(w->dapm, &r);
2937 }
2938 }
2939 }
2940
2941 return 0;
2942}
2943
2825static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, 2944static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
2826 int stream, struct snd_soc_dai *dai, 2945 int stream, struct snd_soc_dai *dai,
2827 int event) 2946 int event)