summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@ti.com>2012-04-18 06:41:11 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-18 13:23:00 -0400
commitec2e3031b65f23f66840b5c89c4b83076831a435 (patch)
treeb85d6a5590fc0eaa3a5e7ca1a67e97b673629e65 /sound/soc/soc-dapm.c
parent0cbe4b36b075e80f3149a91ef640bc7930aa94c7 (diff)
ASoC: dapm: Add API call to query valid DAPM paths
In preparation for ASoC DSP support. Add a DAPM API call to determine whether a DAPM audio path is valid between source and sink widgets. This also takes into account all kcontrol mux and mixer settings in between the source and sink widgets to validate the audio path. This will be used by the DSP core to determine the runtime DAI mappings between FE and BE DAIs in order to run PCM operations. Signed-off-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c122
1 files changed, 112 insertions, 10 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d7ee73a60ca5..214323f53956 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -705,11 +705,51 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
705 } 705 }
706} 706}
707 707
708/* add widget to list if it's not already in the list */
709static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
710 struct snd_soc_dapm_widget *w)
711{
712 struct snd_soc_dapm_widget_list *wlist;
713 int wlistsize, wlistentries, i;
714
715 if (*list == NULL)
716 return -EINVAL;
717
718 wlist = *list;
719
720 /* is this widget already in the list */
721 for (i = 0; i < wlist->num_widgets; i++) {
722 if (wlist->widgets[i] == w)
723 return 0;
724 }
725
726 /* allocate some new space */
727 wlistentries = wlist->num_widgets + 1;
728 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
729 wlistentries * sizeof(struct snd_soc_dapm_widget *);
730 *list = krealloc(wlist, wlistsize, GFP_KERNEL);
731 if (*list == NULL) {
732 dev_err(w->dapm->dev, "can't allocate widget list for %s\n",
733 w->name);
734 return -ENOMEM;
735 }
736 wlist = *list;
737
738 /* insert the widget */
739 dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n",
740 w->name, wlist->num_widgets);
741
742 wlist->widgets[wlist->num_widgets] = w;
743 wlist->num_widgets++;
744 return 1;
745}
746
708/* 747/*
709 * Recursively check for a completed path to an active or physically connected 748 * Recursively check for a completed path to an active or physically connected
710 * output widget. Returns number of complete paths. 749 * output widget. Returns number of complete paths.
711 */ 750 */
712static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) 751static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
752 struct snd_soc_dapm_widget_list **list)
713{ 753{
714 struct snd_soc_dapm_path *path; 754 struct snd_soc_dapm_path *path;
715 int con = 0; 755 int con = 0;
@@ -765,9 +805,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
765 if (path->walked) 805 if (path->walked)
766 continue; 806 continue;
767 807
808 trace_snd_soc_dapm_output_path(widget, path);
809
768 if (path->sink && path->connect) { 810 if (path->sink && path->connect) {
769 path->walked = 1; 811 path->walked = 1;
770 con += is_connected_output_ep(path->sink); 812
813 /* do we need to add this widget to the list ? */
814 if (list) {
815 int err;
816 err = dapm_list_add_widget(list, path->sink);
817 if (err < 0) {
818 dev_err(widget->dapm->dev, "could not add widget %s\n",
819 widget->name);
820 return con;
821 }
822 }
823
824 con += is_connected_output_ep(path->sink, list);
771 } 825 }
772 } 826 }
773 827
@@ -780,7 +834,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
780 * Recursively check for a completed path to an active or physically connected 834 * Recursively check for a completed path to an active or physically connected
781 * input widget. Returns number of complete paths. 835 * input widget. Returns number of complete paths.
782 */ 836 */
783static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) 837static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
838 struct snd_soc_dapm_widget_list **list)
784{ 839{
785 struct snd_soc_dapm_path *path; 840 struct snd_soc_dapm_path *path;
786 int con = 0; 841 int con = 0;
@@ -848,9 +903,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
848 if (path->walked) 903 if (path->walked)
849 continue; 904 continue;
850 905
906 trace_snd_soc_dapm_input_path(widget, path);
907
851 if (path->source && path->connect) { 908 if (path->source && path->connect) {
852 path->walked = 1; 909 path->walked = 1;
853 con += is_connected_input_ep(path->source); 910
911 /* do we need to add this widget to the list ? */
912 if (list) {
913 int err;
914 err = dapm_list_add_widget(list, path->sink);
915 if (err < 0) {
916 dev_err(widget->dapm->dev, "could not add widget %s\n",
917 widget->name);
918 return con;
919 }
920 }
921
922 con += is_connected_input_ep(path->source, list);
854 } 923 }
855 } 924 }
856 925
@@ -859,6 +928,39 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
859 return con; 928 return con;
860} 929}
861 930
931/**
932 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
933 * @dai: the soc DAI.
934 * @stream: stream direction.
935 * @list: list of active widgets for this stream.
936 *
937 * Queries DAPM graph as to whether an valid audio stream path exists for
938 * the initial stream specified by name. This takes into account
939 * current mixer and mux kcontrol settings. Creates list of valid widgets.
940 *
941 * Returns the number of valid paths or negative error.
942 */
943int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
944 struct snd_soc_dapm_widget_list **list)
945{
946 struct snd_soc_card *card = dai->card;
947 int paths;
948
949 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
950 dapm_reset(card);
951
952 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
953 paths = is_connected_output_ep(dai->playback_widget, list);
954 else
955 paths = is_connected_input_ep(dai->playback_widget, list);
956
957 trace_snd_soc_dapm_connected(paths, stream);
958 dapm_clear_walk(&card->dapm);
959 mutex_unlock(&card->dapm_mutex);
960
961 return paths;
962}
963
862/* 964/*
863 * Handler for generic register modifier widget. 965 * Handler for generic register modifier widget.
864 */ 966 */
@@ -915,9 +1017,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
915 1017
916 DAPM_UPDATE_STAT(w, power_checks); 1018 DAPM_UPDATE_STAT(w, power_checks);
917 1019
918 in = is_connected_input_ep(w); 1020 in = is_connected_input_ep(w, NULL);
919 dapm_clear_walk(w->dapm); 1021 dapm_clear_walk(w->dapm);
920 out = is_connected_output_ep(w); 1022 out = is_connected_output_ep(w, NULL);
921 dapm_clear_walk(w->dapm); 1023 dapm_clear_walk(w->dapm);
922 return out != 0 && in != 0; 1024 return out != 0 && in != 0;
923} 1025}
@@ -940,7 +1042,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
940 DAPM_UPDATE_STAT(w, power_checks); 1042 DAPM_UPDATE_STAT(w, power_checks);
941 1043
942 if (w->active) { 1044 if (w->active) {
943 in = is_connected_input_ep(w); 1045 in = is_connected_input_ep(w, NULL);
944 dapm_clear_walk(w->dapm); 1046 dapm_clear_walk(w->dapm);
945 return in != 0; 1047 return in != 0;
946 } else { 1048 } else {
@@ -956,7 +1058,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
956 DAPM_UPDATE_STAT(w, power_checks); 1058 DAPM_UPDATE_STAT(w, power_checks);
957 1059
958 if (w->active) { 1060 if (w->active) {
959 out = is_connected_output_ep(w); 1061 out = is_connected_output_ep(w, NULL);
960 dapm_clear_walk(w->dapm); 1062 dapm_clear_walk(w->dapm);
961 return out != 0; 1063 return out != 0;
962 } else { 1064 } else {
@@ -1558,9 +1660,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
1558 if (!buf) 1660 if (!buf)
1559 return -ENOMEM; 1661 return -ENOMEM;
1560 1662
1561 in = is_connected_input_ep(w); 1663 in = is_connected_input_ep(w, NULL);
1562 dapm_clear_walk(w->dapm); 1664 dapm_clear_walk(w->dapm);
1563 out = is_connected_output_ep(w); 1665 out = is_connected_output_ep(w, NULL);
1564 dapm_clear_walk(w->dapm); 1666 dapm_clear_walk(w->dapm);
1565 1667
1566 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", 1668 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",