diff options
author | Jarkko Nikula <jhnikula@gmail.com> | 2010-12-14 05:18:31 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-12-15 13:01:01 -0500 |
commit | 97c866defc0fc6e18b49603ac19f732f53e79c46 (patch) | |
tree | 66ba8412fad0974ebf9a30c45ad5d81f26607e6e | |
parent | 8ddab3f5107c3955e70e87a632d4d179ddba1189 (diff) |
ASoC: Move widgets from DAPM context to snd_soc_card
Decoupling widgets from DAPM context is required when extending the ASoC
core to cross-device paths. Even the list of widgets are now kept in
struct snd_soc_card, the widget listing in sysfs and debugs remain sorted
per device.
This patch makes possible to build cross-device paths but does not extend
yet the DAPM to handle codec bias and widget power changes of an another
device.
Cross-device paths are registered by listing the widgets from device A in
a map for device B. In case of conflicting widget names between the devices,
a uniform name prefix is needed to separate them. See commit ead9b91
"ASoC: Add optional name_prefix for kcontrol, widget and route names" for
help.
An example below shows a path that connects MONO out of A into Line In of B:
static const struct snd_soc_dapm_route mapA[] = {
{"MONO", NULL, "DAC"},
};
static const struct snd_soc_dapm_route mapB[] = {
{"Line In", NULL, "MONO"},
};
Signed-off-by: Jarkko Nikula <jhnikula@gmail.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | include/sound/soc-dapm.h | 2 | ||||
-rw-r--r-- | include/sound/soc.h | 1 | ||||
-rw-r--r-- | sound/soc/codecs/wm8960.c | 4 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 2 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 69 |
5 files changed, 55 insertions, 23 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 2c1e0eed43d5..c0e7c47469fc 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -462,7 +462,7 @@ struct snd_soc_dapm_widget { | |||
462 | 462 | ||
463 | /* DAPM context */ | 463 | /* DAPM context */ |
464 | struct snd_soc_dapm_context { | 464 | struct snd_soc_dapm_context { |
465 | struct list_head widgets; | 465 | int n_widgets; /* number of widgets in this context */ |
466 | enum snd_soc_bias_level bias_level; | 466 | enum snd_soc_bias_level bias_level; |
467 | enum snd_soc_bias_level suspend_bias_level; | 467 | enum snd_soc_bias_level suspend_bias_level; |
468 | struct delayed_work delayed_work; | 468 | struct delayed_work delayed_work; |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 466895b627b5..d5fb8618fdba 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -661,6 +661,7 @@ struct snd_soc_card { | |||
661 | struct list_head platform_dev_list; | 661 | struct list_head platform_dev_list; |
662 | struct list_head dai_dev_list; | 662 | struct list_head dai_dev_list; |
663 | 663 | ||
664 | struct list_head widgets; | ||
664 | struct list_head paths; | 665 | struct list_head paths; |
665 | 666 | ||
666 | #ifdef CONFIG_DEBUG_FS | 667 | #ifdef CONFIG_DEBUG_FS |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 2c5712dce1d5..054f5737319c 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -418,7 +418,9 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec) | |||
418 | * list each time to find the desired power state do so now | 418 | * list each time to find the desired power state do so now |
419 | * and save the result. | 419 | * and save the result. |
420 | */ | 420 | */ |
421 | list_for_each_entry(w, &codec->dapm.widgets, list) { | 421 | list_for_each_entry(w, &codec->card->widgets, list) { |
422 | if (w->dapm != &codec->dapm) | ||
423 | continue; | ||
422 | if (strcmp(w->name, "LOUT1 PGA") == 0) | 424 | if (strcmp(w->name, "LOUT1 PGA") == 0) |
423 | wm8960->lout1 = w; | 425 | wm8960->lout1 = w; |
424 | if (strcmp(w->name, "ROUT1 PGA") == 0) | 426 | if (strcmp(w->name, "ROUT1 PGA") == 0) |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bdb2ca9da58b..bd183a7ed696 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1879,6 +1879,7 @@ static int soc_probe(struct platform_device *pdev) | |||
1879 | INIT_LIST_HEAD(&card->dai_dev_list); | 1879 | INIT_LIST_HEAD(&card->dai_dev_list); |
1880 | INIT_LIST_HEAD(&card->codec_dev_list); | 1880 | INIT_LIST_HEAD(&card->codec_dev_list); |
1881 | INIT_LIST_HEAD(&card->platform_dev_list); | 1881 | INIT_LIST_HEAD(&card->platform_dev_list); |
1882 | INIT_LIST_HEAD(&card->widgets); | ||
1882 | INIT_LIST_HEAD(&card->paths); | 1883 | INIT_LIST_HEAD(&card->paths); |
1883 | 1884 | ||
1884 | soc_init_card_debugfs(card); | 1885 | soc_init_card_debugfs(card); |
@@ -3481,7 +3482,6 @@ int snd_soc_register_codec(struct device *dev, | |||
3481 | else | 3482 | else |
3482 | codec->compress_type = SND_SOC_FLAT_COMPRESSION; | 3483 | codec->compress_type = SND_SOC_FLAT_COMPRESSION; |
3483 | 3484 | ||
3484 | INIT_LIST_HEAD(&codec->dapm.widgets); | ||
3485 | codec->write = codec_drv->write; | 3485 | codec->write = codec_drv->write; |
3486 | codec->read = codec_drv->read; | 3486 | codec->read = codec_drv->read; |
3487 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 3487 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5d9ec4a3a9f1..8731e89646ae 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -940,7 +940,9 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
940 | /* Check which widgets we need to power and store them in | 940 | /* Check which widgets we need to power and store them in |
941 | * lists indicating if they should be powered up or down. | 941 | * lists indicating if they should be powered up or down. |
942 | */ | 942 | */ |
943 | list_for_each_entry(w, &dapm->widgets, list) { | 943 | list_for_each_entry(w, &card->widgets, list) { |
944 | if (w->dapm != dapm) | ||
945 | continue; | ||
944 | switch (w->id) { | 946 | switch (w->id) { |
945 | case snd_soc_dapm_pre: | 947 | case snd_soc_dapm_pre: |
946 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 948 | dapm_seq_insert(w, &down_list, dapm_down_seq); |
@@ -978,7 +980,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
978 | /* If there are no DAPM widgets then try to figure out power from the | 980 | /* If there are no DAPM widgets then try to figure out power from the |
979 | * event type. | 981 | * event type. |
980 | */ | 982 | */ |
981 | if (list_empty(&dapm->widgets)) { | 983 | if (!dapm->n_widgets) { |
982 | switch (event) { | 984 | switch (event) { |
983 | case SND_SOC_DAPM_STREAM_START: | 985 | case SND_SOC_DAPM_STREAM_START: |
984 | case SND_SOC_DAPM_STREAM_RESUME: | 986 | case SND_SOC_DAPM_STREAM_RESUME: |
@@ -1145,8 +1147,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm) | |||
1145 | if (!dapm->debugfs_dapm) | 1147 | if (!dapm->debugfs_dapm) |
1146 | return; | 1148 | return; |
1147 | 1149 | ||
1148 | list_for_each_entry(w, &dapm->widgets, list) { | 1150 | list_for_each_entry(w, &dapm->card->widgets, list) { |
1149 | if (!w->name) | 1151 | if (!w->name || w->dapm != dapm) |
1150 | continue; | 1152 | continue; |
1151 | 1153 | ||
1152 | d = debugfs_create_file(w->name, 0444, | 1154 | d = debugfs_create_file(w->name, 0444, |
@@ -1241,7 +1243,9 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
1241 | int count = 0; | 1243 | int count = 0; |
1242 | char *state = "not set"; | 1244 | char *state = "not set"; |
1243 | 1245 | ||
1244 | list_for_each_entry(w, &codec->dapm.widgets, list) { | 1246 | list_for_each_entry(w, &codec->card->widgets, list) { |
1247 | if (w->dapm != &codec->dapm) | ||
1248 | continue; | ||
1245 | 1249 | ||
1246 | /* only display widgets that burnm power */ | 1250 | /* only display widgets that burnm power */ |
1247 | switch (w->id) { | 1251 | switch (w->id) { |
@@ -1303,7 +1307,9 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) | |||
1303 | struct snd_soc_dapm_widget *w, *next_w; | 1307 | struct snd_soc_dapm_widget *w, *next_w; |
1304 | struct snd_soc_dapm_path *p, *next_p; | 1308 | struct snd_soc_dapm_path *p, *next_p; |
1305 | 1309 | ||
1306 | list_for_each_entry_safe(w, next_w, &dapm->widgets, list) { | 1310 | list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { |
1311 | if (w->dapm != dapm) | ||
1312 | continue; | ||
1307 | list_del(&w->list); | 1313 | list_del(&w->list); |
1308 | /* | 1314 | /* |
1309 | * remove source and sink paths associated to this widget. | 1315 | * remove source and sink paths associated to this widget. |
@@ -1334,7 +1340,9 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
1334 | { | 1340 | { |
1335 | struct snd_soc_dapm_widget *w; | 1341 | struct snd_soc_dapm_widget *w; |
1336 | 1342 | ||
1337 | list_for_each_entry(w, &dapm->widgets, list) { | 1343 | list_for_each_entry(w, &dapm->card->widgets, list) { |
1344 | if (w->dapm != dapm) | ||
1345 | continue; | ||
1338 | if (!strcmp(w->name, pin)) { | 1346 | if (!strcmp(w->name, pin)) { |
1339 | dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n", | 1347 | dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n", |
1340 | pin, status); | 1348 | pin, status); |
@@ -1370,6 +1378,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
1370 | { | 1378 | { |
1371 | struct snd_soc_dapm_path *path; | 1379 | struct snd_soc_dapm_path *path; |
1372 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 1380 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
1381 | struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; | ||
1373 | const char *sink; | 1382 | const char *sink; |
1374 | const char *control = route->control; | 1383 | const char *control = route->control; |
1375 | const char *source; | 1384 | const char *source; |
@@ -1389,17 +1398,28 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
1389 | source = route->source; | 1398 | source = route->source; |
1390 | } | 1399 | } |
1391 | 1400 | ||
1392 | /* find src and dest widgets */ | 1401 | /* |
1393 | list_for_each_entry(w, &dapm->widgets, list) { | 1402 | * find src and dest widgets over all widgets but favor a widget from |
1394 | 1403 | * current DAPM context | |
1404 | */ | ||
1405 | list_for_each_entry(w, &dapm->card->widgets, list) { | ||
1395 | if (!wsink && !(strcmp(w->name, sink))) { | 1406 | if (!wsink && !(strcmp(w->name, sink))) { |
1396 | wsink = w; | 1407 | wtsink = w; |
1408 | if (w->dapm == dapm) | ||
1409 | wsink = w; | ||
1397 | continue; | 1410 | continue; |
1398 | } | 1411 | } |
1399 | if (!wsource && !(strcmp(w->name, source))) { | 1412 | if (!wsource && !(strcmp(w->name, source))) { |
1400 | wsource = w; | 1413 | wtsource = w; |
1414 | if (w->dapm == dapm) | ||
1415 | wsource = w; | ||
1401 | } | 1416 | } |
1402 | } | 1417 | } |
1418 | /* use widget from another DAPM context if not found from this */ | ||
1419 | if (!wsink) | ||
1420 | wsink = wtsink; | ||
1421 | if (!wsource) | ||
1422 | wsource = wtsource; | ||
1403 | 1423 | ||
1404 | if (wsource == NULL || wsink == NULL) | 1424 | if (wsource == NULL || wsink == NULL) |
1405 | return -ENODEV; | 1425 | return -ENODEV; |
@@ -1537,7 +1557,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
1537 | { | 1557 | { |
1538 | struct snd_soc_dapm_widget *w; | 1558 | struct snd_soc_dapm_widget *w; |
1539 | 1559 | ||
1540 | list_for_each_entry(w, &dapm->widgets, list) | 1560 | list_for_each_entry(w, &dapm->card->widgets, list) |
1541 | { | 1561 | { |
1542 | if (w->new) | 1562 | if (w->new) |
1543 | continue; | 1563 | continue; |
@@ -2037,12 +2057,13 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2037 | else | 2057 | else |
2038 | snprintf(w->name, name_len, "%s", widget->name); | 2058 | snprintf(w->name, name_len, "%s", widget->name); |
2039 | 2059 | ||
2060 | dapm->n_widgets++; | ||
2040 | w->dapm = dapm; | 2061 | w->dapm = dapm; |
2041 | w->codec = dapm->codec; | 2062 | w->codec = dapm->codec; |
2042 | INIT_LIST_HEAD(&w->sources); | 2063 | INIT_LIST_HEAD(&w->sources); |
2043 | INIT_LIST_HEAD(&w->sinks); | 2064 | INIT_LIST_HEAD(&w->sinks); |
2044 | INIT_LIST_HEAD(&w->list); | 2065 | INIT_LIST_HEAD(&w->list); |
2045 | list_add(&w->list, &dapm->widgets); | 2066 | list_add(&w->list, &dapm->card->widgets); |
2046 | 2067 | ||
2047 | /* machine layer set ups unconnected pins and insertions */ | 2068 | /* machine layer set ups unconnected pins and insertions */ |
2048 | w->connected = 1; | 2069 | w->connected = 1; |
@@ -2085,9 +2106,9 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | |||
2085 | { | 2106 | { |
2086 | struct snd_soc_dapm_widget *w; | 2107 | struct snd_soc_dapm_widget *w; |
2087 | 2108 | ||
2088 | list_for_each_entry(w, &dapm->widgets, list) | 2109 | list_for_each_entry(w, &dapm->card->widgets, list) |
2089 | { | 2110 | { |
2090 | if (!w->sname) | 2111 | if (!w->sname || w->dapm != dapm) |
2091 | continue; | 2112 | continue; |
2092 | dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", | 2113 | dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", |
2093 | w->name, w->sname, stream, event); | 2114 | w->name, w->sname, stream, event); |
@@ -2170,7 +2191,9 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | |||
2170 | { | 2191 | { |
2171 | struct snd_soc_dapm_widget *w; | 2192 | struct snd_soc_dapm_widget *w; |
2172 | 2193 | ||
2173 | list_for_each_entry(w, &dapm->widgets, list) { | 2194 | list_for_each_entry(w, &dapm->card->widgets, list) { |
2195 | if (w->dapm != dapm) | ||
2196 | continue; | ||
2174 | if (!strcmp(w->name, pin)) { | 2197 | if (!strcmp(w->name, pin)) { |
2175 | dev_dbg(w->dapm->dev, | 2198 | dev_dbg(w->dapm->dev, |
2176 | "dapm: force enable pin %s\n", pin); | 2199 | "dapm: force enable pin %s\n", pin); |
@@ -2235,7 +2258,9 @@ int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, | |||
2235 | { | 2258 | { |
2236 | struct snd_soc_dapm_widget *w; | 2259 | struct snd_soc_dapm_widget *w; |
2237 | 2260 | ||
2238 | list_for_each_entry(w, &dapm->widgets, list) { | 2261 | list_for_each_entry(w, &dapm->card->widgets, list) { |
2262 | if (w->dapm != dapm) | ||
2263 | continue; | ||
2239 | if (!strcmp(w->name, pin)) | 2264 | if (!strcmp(w->name, pin)) |
2240 | return w->connected; | 2265 | return w->connected; |
2241 | } | 2266 | } |
@@ -2260,7 +2285,9 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, | |||
2260 | { | 2285 | { |
2261 | struct snd_soc_dapm_widget *w; | 2286 | struct snd_soc_dapm_widget *w; |
2262 | 2287 | ||
2263 | list_for_each_entry(w, &dapm->widgets, list) { | 2288 | list_for_each_entry(w, &dapm->card->widgets, list) { |
2289 | if (w->dapm != dapm) | ||
2290 | continue; | ||
2264 | if (!strcmp(w->name, pin)) { | 2291 | if (!strcmp(w->name, pin)) { |
2265 | w->ignore_suspend = 1; | 2292 | w->ignore_suspend = 1; |
2266 | return 0; | 2293 | return 0; |
@@ -2291,7 +2318,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
2291 | LIST_HEAD(down_list); | 2318 | LIST_HEAD(down_list); |
2292 | int powerdown = 0; | 2319 | int powerdown = 0; |
2293 | 2320 | ||
2294 | list_for_each_entry(w, &dapm->widgets, list) { | 2321 | list_for_each_entry(w, &dapm->card->widgets, list) { |
2322 | if (w->dapm != dapm) | ||
2323 | continue; | ||
2295 | if (w->power) { | 2324 | if (w->power) { |
2296 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 2325 | dapm_seq_insert(w, &down_list, dapm_down_seq); |
2297 | w->power = 0; | 2326 | w->power = 0; |