aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-10-03 16:06:40 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-10-04 11:50:20 -0400
commitdb432b414e20b7218bbd91654d7be9c524a4337a (patch)
tree5bd14d5a82768553518184e1bf309ad463ce4384 /sound/soc/soc-dapm.c
parent565631008f6dd27c3e975c2103141f344d80b84e (diff)
ASoC: Do DAPM power checks only for widgets changed since last run
In order to reduce the number of DAPM power checks we run keep a list of widgets which have been changed since the last DAPM run and iterate over that rather than the full widget list. Whenever we change the power state for a widget we add all the source and sink widgets it has to the dirty list, ensuring that all widgets in the path are checked. This covers more widgets than we need to as some of the neighbour widgets won't be connected but it's simpler as a first step. On one system I tried this gave: Power Path Neighbour Before: 207 1939 2461 After: 114 1066 1327 which seems useful. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c61
1 files changed, 55 insertions, 6 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index cb00918b08d6..9d6bb33e6094 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -119,6 +119,17 @@ static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
119 kfree(buf); 119 kfree(buf);
120} 120}
121 121
122static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
123{
124 return !list_empty(&w->dirty);
125}
126
127static void dapm_mark_dirty(struct snd_soc_dapm_widget *w)
128{
129 if (!dapm_dirty_widget(w))
130 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
131}
132
122/* create a new dapm widget */ 133/* create a new dapm widget */
123static inline struct snd_soc_dapm_widget *dapm_cnew_widget( 134static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
124 const struct snd_soc_dapm_widget *_widget) 135 const struct snd_soc_dapm_widget *_widget)
@@ -1208,11 +1219,30 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1208 struct list_head *up_list, 1219 struct list_head *up_list,
1209 struct list_head *down_list) 1220 struct list_head *down_list)
1210{ 1221{
1222 struct snd_soc_dapm_path *path;
1223
1211 if (w->power == power) 1224 if (w->power == power)
1212 return; 1225 return;
1213 1226
1214 trace_snd_soc_dapm_widget_power(w, power); 1227 trace_snd_soc_dapm_widget_power(w, power);
1215 1228
1229 /* If we changed our power state perhaps our neigbours changed
1230 * also. We're not yet smart enough to update relevant
1231 * neighbours when we change the state of a widget, this acts
1232 * as a proxy for that. It will notify more neighbours than
1233 * is ideal.
1234 */
1235 list_for_each_entry(path, &w->sources, list_sink) {
1236 if (path->source) {
1237 dapm_mark_dirty(path->source);
1238 }
1239 }
1240 list_for_each_entry(path, &w->sinks, list_source) {
1241 if (path->sink) {
1242 dapm_mark_dirty(path->sink);
1243 }
1244 }
1245
1216 if (power) 1246 if (power)
1217 dapm_seq_insert(w, up_list, true); 1247 dapm_seq_insert(w, up_list, true);
1218 else 1248 else
@@ -1276,13 +1306,18 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1276 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); 1306 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
1277 1307
1278 /* Check which widgets we need to power and store them in 1308 /* Check which widgets we need to power and store them in
1279 * lists indicating if they should be powered up or down. 1309 * lists indicating if they should be powered up or down. We
1310 * only check widgets that have been flagged as dirty but note
1311 * that new widgets may be added to the dirty list while we
1312 * iterate.
1280 */ 1313 */
1281 list_for_each_entry(w, &card->widgets, list) { 1314 list_for_each_entry(w, &card->dapm_dirty, dirty) {
1282 dapm_power_one_widget(w, &up_list, &down_list); 1315 dapm_power_one_widget(w, &up_list, &down_list);
1283 } 1316 }
1284 1317
1285 list_for_each_entry(w, &card->widgets, list) { 1318 list_for_each_entry(w, &card->widgets, list) {
1319 list_del_init(&w->dirty);
1320
1286 if (w->power) { 1321 if (w->power) {
1287 d = w->dapm; 1322 d = w->dapm;
1288 1323
@@ -1573,14 +1608,20 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1573 1608
1574 found = 1; 1609 found = 1;
1575 /* we now need to match the string in the enum to the path */ 1610 /* we now need to match the string in the enum to the path */
1576 if (!(strcmp(path->name, e->texts[mux]))) 1611 if (!(strcmp(path->name, e->texts[mux]))) {
1577 path->connect = 1; /* new connection */ 1612 path->connect = 1; /* new connection */
1578 else 1613 dapm_mark_dirty(path->source);
1614 } else {
1615 if (path->connect)
1616 dapm_mark_dirty(path->source);
1579 path->connect = 0; /* old connection must be powered down */ 1617 path->connect = 0; /* old connection must be powered down */
1618 }
1580 } 1619 }
1581 1620
1582 if (found) 1621 if (found) {
1622 dapm_mark_dirty(widget);
1583 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); 1623 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
1624 }
1584 1625
1585 return 0; 1626 return 0;
1586} 1627}
@@ -1605,10 +1646,13 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1605 /* found, now check type */ 1646 /* found, now check type */
1606 found = 1; 1647 found = 1;
1607 path->connect = connect; 1648 path->connect = connect;
1649 dapm_mark_dirty(path->source);
1608 } 1650 }
1609 1651
1610 if (found) 1652 if (found) {
1653 dapm_mark_dirty(widget);
1611 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); 1654 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
1655 }
1612 1656
1613 return 0; 1657 return 0;
1614} 1658}
@@ -1752,6 +1796,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
1752 w->connected = status; 1796 w->connected = status;
1753 if (status == 0) 1797 if (status == 0)
1754 w->force = 0; 1798 w->force = 0;
1799 dapm_mark_dirty(w);
1755 1800
1756 return 0; 1801 return 0;
1757} 1802}
@@ -2107,6 +2152,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
2107 2152
2108 w->new = 1; 2153 w->new = 1;
2109 2154
2155 list_add(&w->dirty, &(w->dapm->card->dapm_dirty));
2110 dapm_debugfs_add_widget(w); 2156 dapm_debugfs_add_widget(w);
2111 } 2157 }
2112 2158
@@ -2588,6 +2634,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
2588 INIT_LIST_HEAD(&w->sources); 2634 INIT_LIST_HEAD(&w->sources);
2589 INIT_LIST_HEAD(&w->sinks); 2635 INIT_LIST_HEAD(&w->sinks);
2590 INIT_LIST_HEAD(&w->list); 2636 INIT_LIST_HEAD(&w->list);
2637 INIT_LIST_HEAD(&w->dirty);
2591 list_add(&w->list, &dapm->card->widgets); 2638 list_add(&w->list, &dapm->card->widgets);
2592 2639
2593 /* machine layer set ups unconnected pins and insertions */ 2640 /* machine layer set ups unconnected pins and insertions */
@@ -2638,6 +2685,7 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
2638 dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", 2685 dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
2639 w->name, w->sname, stream, event); 2686 w->name, w->sname, stream, event);
2640 if (strstr(w->sname, stream)) { 2687 if (strstr(w->sname, stream)) {
2688 dapm_mark_dirty(w);
2641 switch(event) { 2689 switch(event) {
2642 case SND_SOC_DAPM_STREAM_START: 2690 case SND_SOC_DAPM_STREAM_START:
2643 w->active = 1; 2691 w->active = 1;
@@ -2727,6 +2775,7 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
2727 dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin); 2775 dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
2728 w->connected = 1; 2776 w->connected = 1;
2729 w->force = 1; 2777 w->force = 1;
2778 dapm_mark_dirty(w);
2730 2779
2731 return 0; 2780 return 0;
2732} 2781}