aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-10-25 11:41:59 -0400
committerMark Brown <broonie@kernel.org>2014-10-27 20:19:59 -0400
commit6dd98b0a3e58b7b48a422802b5610b95ef5128eb (patch)
tree4ccd24a78ce2b20cca72261dbaa9858d1d8ed470
parent5fe5b767dc6fb3df6fa6eaa8e05b727914f2bb4c (diff)
ASoC: dapm: Introduce toplevel widget categories
DAPM widgets can be classified into four categories: * supply: Supply widgets do not affect the power state of their non-supply widget neighbors and unlike other widgets a supply widget is not powered up when it is on an active path, but when at least on of its neighbors is powered up. * source: A source is a widget that receives data from outside the DAPM graph or generates data. This can for example be a microphone, the playback DMA or a signal generator. A source widget will be considered powered up if there is an active path to a sink widget. * sink: A sink is a widget that transmits data to somewhere outside of the DAPM graph. This can e.g. be a speaker or the capture DMA. A sink widget will be considered powered up if there is an active path from a source widget. * normal: Normal widgets are widgets not covered by the categories above. A normal widget will be considered powered up if it is on an active path between a source widget and a sink widget. The way the number of input and output paths for a widget is calculated depends on its category. There are a bunch of factors which decide which category a widget is. Currently there is no formal classification of these categories and we calculate the category of the widget based on these factors whenever we want to know it. This is at least once for every widget during each power update sequence. The factors which determine the category of the widgets are mostly static though and if at all change rather seldom. This patch introduces three new per widget flags, one for each of non-normal widgets categories. Instead of re-computing the category each time we want to know them the flags will be checked. For the majority of widgets the category is solely determined by the widget id, which means it never changes and only has to be set once when the widget is created. The only widgets with dynamic categories are: snd_soc_dapm_dai_out: Is considered a sink iff the capture stream is active, otherwise normal. snd_soc_dapm_dai_in: Is considered a source iff the playback stream is active, otherwise normal. snd_soc_dapm_input: Is considered a sink iff it has no outgoing paths, otherwise normal. snd_soc_dapm_output: Is considered a source iff it has no incoming paths, otherwise normal. snd_soc_dapm_line: Is considered a sink iff it has no outgoing paths and is considered a source iff it has no incoming paths, otherwise normal. For snd_soc_dapm_dai_out/snd_soc_dapm_dai_in widgets the category will be updated when a stream is started or stopped. For the other dynamic widgets the category will be updated when a path connecting to it is added or removed. Introducing those new widget categories allows to make is_connected_{output,input}_ep, which are among the hottest paths of the DAPM algorithm, more generic and significantly shorter. The before and after sizes for is_connected_{output,input}_ep are: On ARM (defconfig + CONFIG_SND_SOC): function old new delta is_connected_output_ep 480 340 -140 is_connected_input_ep 456 352 -104 On amd64 (defconfig + CONFIG_SND_SOC): function old new delta is_connected_output_ep 579 427 -152 is_connected_input_ep 563 427 -136 Which is about a 25%-30% decrease, other architectures are expected to have similar numbers. At the same time the size of the snd_soc_dapm_widget struct does not change since the new flags are stored in the same word as the existing flags. Note: that since the per widget 'ext' flag was only used to decide whether a snd_soc_dapm_input or snd_soc_dapm_output widget was a source or a sink it is now unused and can be removed. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--include/sound/soc-dapm.h4
-rw-r--r--sound/soc/soc-dapm.c210
2 files changed, 95 insertions, 119 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index ebb93f29e4f3..8cf3aad30864 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -543,11 +543,13 @@ struct snd_soc_dapm_widget {
543 unsigned char active:1; /* active stream on DAC, ADC's */ 543 unsigned char active:1; /* active stream on DAC, ADC's */
544 unsigned char connected:1; /* connected codec pin */ 544 unsigned char connected:1; /* connected codec pin */
545 unsigned char new:1; /* cnew complete */ 545 unsigned char new:1; /* cnew complete */
546 unsigned char ext:1; /* has external widgets */
547 unsigned char force:1; /* force state */ 546 unsigned char force:1; /* force state */
548 unsigned char ignore_suspend:1; /* kept enabled over suspend */ 547 unsigned char ignore_suspend:1; /* kept enabled over suspend */
549 unsigned char new_power:1; /* power from this run */ 548 unsigned char new_power:1; /* power from this run */
550 unsigned char power_checked:1; /* power checked this run */ 549 unsigned char power_checked:1; /* power checked this run */
550 unsigned char is_supply:1; /* Widget is a supply type widget */
551 unsigned char is_sink:1; /* Widget is a sink type widget */
552 unsigned char is_source:1; /* Widget is a source type widget */
551 int subseq; /* sort within widget type */ 553 int subseq; /* sort within widget type */
552 554
553 int (*power_check)(struct snd_soc_dapm_widget *w); 555 int (*power_check)(struct snd_soc_dapm_widget *w);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c49df10d1c33..2cad5f77ec60 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -821,43 +821,12 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
821 821
822 DAPM_UPDATE_STAT(widget, path_checks); 822 DAPM_UPDATE_STAT(widget, path_checks);
823 823
824 switch (widget->id) { 824 if (widget->is_supply)
825 case snd_soc_dapm_supply:
826 case snd_soc_dapm_regulator_supply:
827 case snd_soc_dapm_clock_supply:
828 case snd_soc_dapm_kcontrol:
829 return 0; 825 return 0;
830 default:
831 break;
832 }
833 826
834 switch (widget->id) { 827 if (widget->is_sink && widget->connected) {
835 case snd_soc_dapm_adc: 828 widget->outputs = snd_soc_dapm_suspend_check(widget);
836 case snd_soc_dapm_aif_out: 829 return widget->outputs;
837 case snd_soc_dapm_dai_out:
838 if (widget->active) {
839 widget->outputs = snd_soc_dapm_suspend_check(widget);
840 return widget->outputs;
841 }
842 default:
843 break;
844 }
845
846 if (widget->connected) {
847 /* connected pin ? */
848 if (widget->id == snd_soc_dapm_output && !widget->ext) {
849 widget->outputs = snd_soc_dapm_suspend_check(widget);
850 return widget->outputs;
851 }
852
853 /* connected jack or spk ? */
854 if (widget->id == snd_soc_dapm_hp ||
855 widget->id == snd_soc_dapm_spk ||
856 (widget->id == snd_soc_dapm_line &&
857 !list_empty(&widget->sources))) {
858 widget->outputs = snd_soc_dapm_suspend_check(widget);
859 return widget->outputs;
860 }
861 } 830 }
862 831
863 list_for_each_entry(path, &widget->sinks, list_source) { 832 list_for_each_entry(path, &widget->sinks, list_source) {
@@ -913,55 +882,12 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
913 882
914 DAPM_UPDATE_STAT(widget, path_checks); 883 DAPM_UPDATE_STAT(widget, path_checks);
915 884
916 switch (widget->id) { 885 if (widget->is_supply)
917 case snd_soc_dapm_supply:
918 case snd_soc_dapm_regulator_supply:
919 case snd_soc_dapm_clock_supply:
920 case snd_soc_dapm_kcontrol:
921 return 0; 886 return 0;
922 default:
923 break;
924 }
925
926 /* active stream ? */
927 switch (widget->id) {
928 case snd_soc_dapm_dac:
929 case snd_soc_dapm_aif_in:
930 case snd_soc_dapm_dai_in:
931 if (widget->active) {
932 widget->inputs = snd_soc_dapm_suspend_check(widget);
933 return widget->inputs;
934 }
935 default:
936 break;
937 }
938
939 if (widget->connected) {
940 /* connected pin ? */
941 if (widget->id == snd_soc_dapm_input && !widget->ext) {
942 widget->inputs = snd_soc_dapm_suspend_check(widget);
943 return widget->inputs;
944 }
945 887
946 /* connected VMID/Bias for lower pops */ 888 if (widget->is_source && widget->connected) {
947 if (widget->id == snd_soc_dapm_vmid) { 889 widget->inputs = snd_soc_dapm_suspend_check(widget);
948 widget->inputs = snd_soc_dapm_suspend_check(widget); 890 return widget->inputs;
949 return widget->inputs;
950 }
951
952 /* connected jack ? */
953 if (widget->id == snd_soc_dapm_mic ||
954 (widget->id == snd_soc_dapm_line &&
955 !list_empty(&widget->sinks))) {
956 widget->inputs = snd_soc_dapm_suspend_check(widget);
957 return widget->inputs;
958 }
959
960 /* signal generator */
961 if (widget->id == snd_soc_dapm_siggen) {
962 widget->inputs = snd_soc_dapm_suspend_check(widget);
963 return widget->inputs;
964 }
965 } 891 }
966 892
967 list_for_each_entry(path, &widget->sources, list_sink) { 893 list_for_each_entry(path, &widget->sources, list_sink) {
@@ -1554,18 +1480,11 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1554 list_for_each_entry(path, &w->sources, list_sink) 1480 list_for_each_entry(path, &w->sources, list_sink)
1555 dapm_widget_set_peer_power(path->source, power, path->connect); 1481 dapm_widget_set_peer_power(path->source, power, path->connect);
1556 1482
1557 switch (w->id) { 1483 /* Supplies can't affect their outputs, only their inputs */
1558 case snd_soc_dapm_supply: 1484 if (!w->is_supply) {
1559 case snd_soc_dapm_regulator_supply:
1560 case snd_soc_dapm_clock_supply:
1561 case snd_soc_dapm_kcontrol:
1562 /* Supplies can't affect their outputs, only their inputs */
1563 break;
1564 default:
1565 list_for_each_entry(path, &w->sinks, list_source) 1485 list_for_each_entry(path, &w->sinks, list_source)
1566 dapm_widget_set_peer_power(path->sink, power, 1486 dapm_widget_set_peer_power(path->sink, power,
1567 path->connect); 1487 path->connect);
1568 break;
1569 } 1488 }
1570 1489
1571 if (power) 1490 if (power)
@@ -2226,6 +2145,53 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
2226} 2145}
2227EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); 2146EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
2228 2147
2148/*
2149 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2150 * @w: The widget for which to update the flags
2151 *
2152 * Some widgets have a dynamic category which depends on which neighbors they
2153 * are connected to. This function update the category for these widgets.
2154 *
2155 * This function must be called whenever a path is added or removed to a widget.
2156 */
2157static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2158{
2159 struct snd_soc_dapm_path *p;
2160
2161 switch (w->id) {
2162 case snd_soc_dapm_input:
2163 w->is_source = 1;
2164 list_for_each_entry(p, &w->sources, list_sink) {
2165 if (p->source->id == snd_soc_dapm_micbias ||
2166 p->source->id == snd_soc_dapm_mic ||
2167 p->source->id == snd_soc_dapm_line ||
2168 p->source->id == snd_soc_dapm_output) {
2169 w->is_source = 0;
2170 break;
2171 }
2172 }
2173 break;
2174 case snd_soc_dapm_output:
2175 w->is_sink = 1;
2176 list_for_each_entry(p, &w->sinks, list_source) {
2177 if (p->sink->id == snd_soc_dapm_spk ||
2178 p->sink->id == snd_soc_dapm_hp ||
2179 p->sink->id == snd_soc_dapm_line ||
2180 p->sink->id == snd_soc_dapm_input) {
2181 w->is_sink = 0;
2182 break;
2183 }
2184 }
2185 break;
2186 case snd_soc_dapm_line:
2187 w->is_sink = !list_empty(&w->sources);
2188 w->is_source = !list_empty(&w->sinks);
2189 break;
2190 default:
2191 break;
2192 }
2193}
2194
2229static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, 2195static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2230 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, 2196 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2231 const char *control, 2197 const char *control,
@@ -2247,22 +2213,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2247 INIT_LIST_HEAD(&path->list_source); 2213 INIT_LIST_HEAD(&path->list_source);
2248 INIT_LIST_HEAD(&path->list_sink); 2214 INIT_LIST_HEAD(&path->list_sink);
2249 2215
2250 /* check for external widgets */
2251 if (wsink->id == snd_soc_dapm_input) {
2252 if (wsource->id == snd_soc_dapm_micbias ||
2253 wsource->id == snd_soc_dapm_mic ||
2254 wsource->id == snd_soc_dapm_line ||
2255 wsource->id == snd_soc_dapm_output)
2256 wsink->ext = 1;
2257 }
2258 if (wsource->id == snd_soc_dapm_output) {
2259 if (wsink->id == snd_soc_dapm_spk ||
2260 wsink->id == snd_soc_dapm_hp ||
2261 wsink->id == snd_soc_dapm_line ||
2262 wsink->id == snd_soc_dapm_input)
2263 wsource->ext = 1;
2264 }
2265
2266 /* connect static paths */ 2216 /* connect static paths */
2267 if (control == NULL) { 2217 if (control == NULL) {
2268 path->connect = 1; 2218 path->connect = 1;
@@ -2294,6 +2244,9 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2294 list_add(&path->list_sink, &wsink->sources); 2244 list_add(&path->list_sink, &wsink->sources);
2295 list_add(&path->list_source, &wsource->sinks); 2245 list_add(&path->list_source, &wsource->sinks);
2296 2246
2247 dapm_update_widget_flags(wsource);
2248 dapm_update_widget_flags(wsink);
2249
2297 dapm_mark_dirty(wsource, "Route added"); 2250 dapm_mark_dirty(wsource, "Route added");
2298 dapm_mark_dirty(wsink, "Route added"); 2251 dapm_mark_dirty(wsink, "Route added");
2299 2252
@@ -2377,6 +2330,7 @@ err:
2377static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, 2330static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2378 const struct snd_soc_dapm_route *route) 2331 const struct snd_soc_dapm_route *route)
2379{ 2332{
2333 struct snd_soc_dapm_widget *wsource, *wsink;
2380 struct snd_soc_dapm_path *path, *p; 2334 struct snd_soc_dapm_path *path, *p;
2381 const char *sink; 2335 const char *sink;
2382 const char *source; 2336 const char *source;
@@ -2414,10 +2368,17 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2414 } 2368 }
2415 2369
2416 if (path) { 2370 if (path) {
2417 dapm_mark_dirty(path->source, "Route removed"); 2371 wsource = path->source;
2418 dapm_mark_dirty(path->sink, "Route removed"); 2372 wsink = path->sink;
2373
2374 dapm_mark_dirty(wsource, "Route removed");
2375 dapm_mark_dirty(wsink, "Route removed");
2419 2376
2420 dapm_free_path(path); 2377 dapm_free_path(path);
2378
2379 /* Update any path related flags */
2380 dapm_update_widget_flags(wsource);
2381 dapm_update_widget_flags(wsink);
2421 } else { 2382 } else {
2422 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", 2383 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
2423 source, sink); 2384 source, sink);
@@ -2975,26 +2936,33 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
2975 } 2936 }
2976 2937
2977 switch (w->id) { 2938 switch (w->id) {
2978 case snd_soc_dapm_switch: 2939 case snd_soc_dapm_mic:
2979 case snd_soc_dapm_mixer: 2940 case snd_soc_dapm_input:
2980 case snd_soc_dapm_mixer_named_ctl: 2941 w->is_source = 1;
2981 w->power_check = dapm_generic_check_power; 2942 w->power_check = dapm_generic_check_power;
2982 break; 2943 break;
2983 case snd_soc_dapm_mux: 2944 case snd_soc_dapm_spk:
2945 case snd_soc_dapm_hp:
2946 case snd_soc_dapm_output:
2947 w->is_sink = 1;
2984 w->power_check = dapm_generic_check_power; 2948 w->power_check = dapm_generic_check_power;
2985 break; 2949 break;
2950 case snd_soc_dapm_vmid:
2951 case snd_soc_dapm_siggen:
2952 w->is_source = 1;
2953 w->power_check = dapm_always_on_check_power;
2954 break;
2955 case snd_soc_dapm_mux:
2956 case snd_soc_dapm_switch:
2957 case snd_soc_dapm_mixer:
2958 case snd_soc_dapm_mixer_named_ctl:
2986 case snd_soc_dapm_adc: 2959 case snd_soc_dapm_adc:
2987 case snd_soc_dapm_aif_out: 2960 case snd_soc_dapm_aif_out:
2988 case snd_soc_dapm_dac: 2961 case snd_soc_dapm_dac:
2989 case snd_soc_dapm_aif_in: 2962 case snd_soc_dapm_aif_in:
2990 case snd_soc_dapm_pga: 2963 case snd_soc_dapm_pga:
2991 case snd_soc_dapm_out_drv: 2964 case snd_soc_dapm_out_drv:
2992 case snd_soc_dapm_input:
2993 case snd_soc_dapm_output:
2994 case snd_soc_dapm_micbias: 2965 case snd_soc_dapm_micbias:
2995 case snd_soc_dapm_spk:
2996 case snd_soc_dapm_hp:
2997 case snd_soc_dapm_mic:
2998 case snd_soc_dapm_line: 2966 case snd_soc_dapm_line:
2999 case snd_soc_dapm_dai_link: 2967 case snd_soc_dapm_dai_link:
3000 case snd_soc_dapm_dai_out: 2968 case snd_soc_dapm_dai_out:
@@ -3005,6 +2973,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3005 case snd_soc_dapm_regulator_supply: 2973 case snd_soc_dapm_regulator_supply:
3006 case snd_soc_dapm_clock_supply: 2974 case snd_soc_dapm_clock_supply:
3007 case snd_soc_dapm_kcontrol: 2975 case snd_soc_dapm_kcontrol:
2976 w->is_supply = 1;
3008 w->power_check = dapm_supply_check_power; 2977 w->power_check = dapm_supply_check_power;
3009 break; 2978 break;
3010 default: 2979 default:
@@ -3368,6 +3337,11 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3368 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: 3337 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3369 break; 3338 break;
3370 } 3339 }
3340
3341 if (w->id == snd_soc_dapm_dai_in)
3342 w->is_source = w->active;
3343 else
3344 w->is_sink = w->active;
3371 } 3345 }
3372} 3346}
3373 3347