aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/sound/soc-dapm.h5
-rw-r--r--include/trace/events/asoc.h80
-rw-r--r--sound/soc/soc-dapm.c122
3 files changed, 197 insertions, 10 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index bea0c8658aa0..e3833d9f1914 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -321,6 +321,7 @@ struct snd_soc_dapm_pin;
321struct snd_soc_dapm_route; 321struct snd_soc_dapm_route;
322struct snd_soc_dapm_context; 322struct snd_soc_dapm_context;
323struct regulator; 323struct regulator;
324struct snd_soc_dapm_widget_list;
324 325
325int dapm_reg_event(struct snd_soc_dapm_widget *w, 326int dapm_reg_event(struct snd_soc_dapm_widget *w,
326 struct snd_kcontrol *kcontrol, int event); 327 struct snd_kcontrol *kcontrol, int event);
@@ -403,6 +404,10 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
403/* Mostly internal - should not normally be used */ 404/* Mostly internal - should not normally be used */
404void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason); 405void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
405 406
407/* dapm path query */
408int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
409 struct snd_soc_dapm_widget_list **list);
410
406/* dapm widget types */ 411/* dapm widget types */
407enum snd_soc_dapm_type { 412enum snd_soc_dapm_type {
408 snd_soc_dapm_input = 0, /* input pin */ 413 snd_soc_dapm_input = 0, /* input pin */
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index ab26f8aa3c78..6d8efb1cc8ce 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -7,6 +7,8 @@
7#include <linux/ktime.h> 7#include <linux/ktime.h>
8#include <linux/tracepoint.h> 8#include <linux/tracepoint.h>
9 9
10#define DAPM_DIRECT "(direct)"
11
10struct snd_soc_jack; 12struct snd_soc_jack;
11struct snd_soc_codec; 13struct snd_soc_codec;
12struct snd_soc_platform; 14struct snd_soc_platform;
@@ -241,6 +243,84 @@ TRACE_EVENT(snd_soc_dapm_walk_done,
241 (int)__entry->path_checks, (int)__entry->neighbour_checks) 243 (int)__entry->path_checks, (int)__entry->neighbour_checks)
242); 244);
243 245
246TRACE_EVENT(snd_soc_dapm_output_path,
247
248 TP_PROTO(struct snd_soc_dapm_widget *widget,
249 struct snd_soc_dapm_path *path),
250
251 TP_ARGS(widget, path),
252
253 TP_STRUCT__entry(
254 __string( wname, widget->name )
255 __string( pname, path->name ? path->name : DAPM_DIRECT)
256 __string( psname, path->sink->name )
257 __field( int, path_sink )
258 __field( int, path_connect )
259 ),
260
261 TP_fast_assign(
262 __assign_str(wname, widget->name);
263 __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
264 __assign_str(psname, path->sink->name);
265 __entry->path_connect = path->connect;
266 __entry->path_sink = (int)path->sink;
267 ),
268
269 TP_printk("%c%s -> %s -> %s\n",
270 (int) __entry->path_sink &&
271 (int) __entry->path_connect ? '*' : ' ',
272 __get_str(wname), __get_str(pname), __get_str(psname))
273);
274
275TRACE_EVENT(snd_soc_dapm_input_path,
276
277 TP_PROTO(struct snd_soc_dapm_widget *widget,
278 struct snd_soc_dapm_path *path),
279
280 TP_ARGS(widget, path),
281
282 TP_STRUCT__entry(
283 __string( wname, widget->name )
284 __string( pname, path->name ? path->name : DAPM_DIRECT)
285 __string( psname, path->source->name )
286 __field( int, path_source )
287 __field( int, path_connect )
288 ),
289
290 TP_fast_assign(
291 __assign_str(wname, widget->name);
292 __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
293 __assign_str(psname, path->source->name);
294 __entry->path_connect = path->connect;
295 __entry->path_source = (int)path->source;
296 ),
297
298 TP_printk("%c%s <- %s <- %s\n",
299 (int) __entry->path_source &&
300 (int) __entry->path_connect ? '*' : ' ',
301 __get_str(wname), __get_str(pname), __get_str(psname))
302);
303
304TRACE_EVENT(snd_soc_dapm_connected,
305
306 TP_PROTO(int paths, int stream),
307
308 TP_ARGS(paths, stream),
309
310 TP_STRUCT__entry(
311 __field( int, paths )
312 __field( int, stream )
313 ),
314
315 TP_fast_assign(
316 __entry->paths = paths;
317 __entry->stream = stream;
318 ),
319
320 TP_printk("%s: found %d paths\n",
321 __entry->stream ? "capture" : "playback", __entry->paths)
322);
323
244TRACE_EVENT(snd_soc_jack_irq, 324TRACE_EVENT(snd_soc_jack_irq,
245 325
246 TP_PROTO(const char *name), 326 TP_PROTO(const char *name),
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",