aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
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 /sound/soc/soc-dapm.c
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>
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c135
1 files changed, 127 insertions, 8 deletions
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)