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>
This commit is contained in:
Jarkko Nikula 2010-12-14 12:18:31 +02:00 committed by Mark Brown
parent 8ddab3f510
commit 97c866defc
5 changed files with 55 additions and 23 deletions

View File

@ -462,7 +462,7 @@ struct snd_soc_dapm_widget {
/* DAPM context */ /* DAPM context */
struct snd_soc_dapm_context { struct snd_soc_dapm_context {
struct list_head widgets; int n_widgets; /* number of widgets in this context */
enum snd_soc_bias_level bias_level; enum snd_soc_bias_level bias_level;
enum snd_soc_bias_level suspend_bias_level; enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work; struct delayed_work delayed_work;

View File

@ -661,6 +661,7 @@ struct snd_soc_card {
struct list_head platform_dev_list; struct list_head platform_dev_list;
struct list_head dai_dev_list; struct list_head dai_dev_list;
struct list_head widgets;
struct list_head paths; struct list_head paths;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS

View File

@ -418,7 +418,9 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
* list each time to find the desired power state do so now * list each time to find the desired power state do so now
* and save the result. * and save the result.
*/ */
list_for_each_entry(w, &codec->dapm.widgets, list) { list_for_each_entry(w, &codec->card->widgets, list) {
if (w->dapm != &codec->dapm)
continue;
if (strcmp(w->name, "LOUT1 PGA") == 0) if (strcmp(w->name, "LOUT1 PGA") == 0)
wm8960->lout1 = w; wm8960->lout1 = w;
if (strcmp(w->name, "ROUT1 PGA") == 0) if (strcmp(w->name, "ROUT1 PGA") == 0)

View File

@ -1879,6 +1879,7 @@ static int soc_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&card->dai_dev_list); INIT_LIST_HEAD(&card->dai_dev_list);
INIT_LIST_HEAD(&card->codec_dev_list); INIT_LIST_HEAD(&card->codec_dev_list);
INIT_LIST_HEAD(&card->platform_dev_list); INIT_LIST_HEAD(&card->platform_dev_list);
INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths); INIT_LIST_HEAD(&card->paths);
soc_init_card_debugfs(card); soc_init_card_debugfs(card);
@ -3481,7 +3482,6 @@ int snd_soc_register_codec(struct device *dev,
else else
codec->compress_type = SND_SOC_FLAT_COMPRESSION; codec->compress_type = SND_SOC_FLAT_COMPRESSION;
INIT_LIST_HEAD(&codec->dapm.widgets);
codec->write = codec_drv->write; codec->write = codec_drv->write;
codec->read = codec_drv->read; codec->read = codec_drv->read;
codec->dapm.bias_level = SND_SOC_BIAS_OFF; codec->dapm.bias_level = SND_SOC_BIAS_OFF;

View File

@ -940,7 +940,9 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
/* Check which widgets we need to power and store them in /* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down. * lists indicating if they should be powered up or down.
*/ */
list_for_each_entry(w, &dapm->widgets, list) { list_for_each_entry(w, &card->widgets, list) {
if (w->dapm != dapm)
continue;
switch (w->id) { switch (w->id) {
case snd_soc_dapm_pre: case snd_soc_dapm_pre:
dapm_seq_insert(w, &down_list, dapm_down_seq); 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)
/* If there are no DAPM widgets then try to figure out power from the /* If there are no DAPM widgets then try to figure out power from the
* event type. * event type.
*/ */
if (list_empty(&dapm->widgets)) { if (!dapm->n_widgets) {
switch (event) { switch (event) {
case SND_SOC_DAPM_STREAM_START: case SND_SOC_DAPM_STREAM_START:
case SND_SOC_DAPM_STREAM_RESUME: case SND_SOC_DAPM_STREAM_RESUME:
@ -1145,8 +1147,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
if (!dapm->debugfs_dapm) if (!dapm->debugfs_dapm)
return; return;
list_for_each_entry(w, &dapm->widgets, list) { list_for_each_entry(w, &dapm->card->widgets, list) {
if (!w->name) if (!w->name || w->dapm != dapm)
continue; continue;
d = debugfs_create_file(w->name, 0444, d = debugfs_create_file(w->name, 0444,
@ -1241,7 +1243,9 @@ static ssize_t dapm_widget_show(struct device *dev,
int count = 0; int count = 0;
char *state = "not set"; char *state = "not set";
list_for_each_entry(w, &codec->dapm.widgets, list) { list_for_each_entry(w, &codec->card->widgets, list) {
if (w->dapm != &codec->dapm)
continue;
/* only display widgets that burnm power */ /* only display widgets that burnm power */
switch (w->id) { switch (w->id) {
@ -1303,7 +1307,9 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
struct snd_soc_dapm_widget *w, *next_w; struct snd_soc_dapm_widget *w, *next_w;
struct snd_soc_dapm_path *p, *next_p; struct snd_soc_dapm_path *p, *next_p;
list_for_each_entry_safe(w, next_w, &dapm->widgets, list) { list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
if (w->dapm != dapm)
continue;
list_del(&w->list); list_del(&w->list);
/* /*
* remove source and sink paths associated to this widget. * 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,
{ {
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
list_for_each_entry(w, &dapm->widgets, list) { list_for_each_entry(w, &dapm->card->widgets, list) {
if (w->dapm != dapm)
continue;
if (!strcmp(w->name, pin)) { if (!strcmp(w->name, pin)) {
dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n", dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n",
pin, status); pin, status);
@ -1370,6 +1378,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
{ {
struct snd_soc_dapm_path *path; struct snd_soc_dapm_path *path;
struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
const char *sink; const char *sink;
const char *control = route->control; const char *control = route->control;
const char *source; const char *source;
@ -1389,17 +1398,28 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
source = route->source; source = route->source;
} }
/* find src and dest widgets */ /*
list_for_each_entry(w, &dapm->widgets, list) { * find src and dest widgets over all widgets but favor a widget from
* current DAPM context
*/
list_for_each_entry(w, &dapm->card->widgets, list) {
if (!wsink && !(strcmp(w->name, sink))) { if (!wsink && !(strcmp(w->name, sink))) {
wsink = w; wtsink = w;
if (w->dapm == dapm)
wsink = w;
continue; continue;
} }
if (!wsource && !(strcmp(w->name, source))) { if (!wsource && !(strcmp(w->name, source))) {
wsource = w; wtsource = w;
if (w->dapm == dapm)
wsource = w;
} }
} }
/* use widget from another DAPM context if not found from this */
if (!wsink)
wsink = wtsink;
if (!wsource)
wsource = wtsource;
if (wsource == NULL || wsink == NULL) if (wsource == NULL || wsink == NULL)
return -ENODEV; return -ENODEV;
@ -1537,7 +1557,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
{ {
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
list_for_each_entry(w, &dapm->widgets, list) list_for_each_entry(w, &dapm->card->widgets, list)
{ {
if (w->new) if (w->new)
continue; continue;
@ -2037,12 +2057,13 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
else else
snprintf(w->name, name_len, "%s", widget->name); snprintf(w->name, name_len, "%s", widget->name);
dapm->n_widgets++;
w->dapm = dapm; w->dapm = dapm;
w->codec = dapm->codec; w->codec = dapm->codec;
INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sources);
INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->sinks);
INIT_LIST_HEAD(&w->list); INIT_LIST_HEAD(&w->list);
list_add(&w->list, &dapm->widgets); list_add(&w->list, &dapm->card->widgets);
/* machine layer set ups unconnected pins and insertions */ /* machine layer set ups unconnected pins and insertions */
w->connected = 1; w->connected = 1;
@ -2085,9 +2106,9 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
{ {
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
list_for_each_entry(w, &dapm->widgets, list) list_for_each_entry(w, &dapm->card->widgets, list)
{ {
if (!w->sname) if (!w->sname || w->dapm != dapm)
continue; continue;
dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
w->name, w->sname, stream, event); w->name, w->sname, stream, event);
@ -2170,7 +2191,9 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
{ {
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
list_for_each_entry(w, &dapm->widgets, list) { list_for_each_entry(w, &dapm->card->widgets, list) {
if (w->dapm != dapm)
continue;
if (!strcmp(w->name, pin)) { if (!strcmp(w->name, pin)) {
dev_dbg(w->dapm->dev, dev_dbg(w->dapm->dev,
"dapm: force enable pin %s\n", pin); "dapm: force enable pin %s\n", pin);
@ -2235,7 +2258,9 @@ int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
{ {
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
list_for_each_entry(w, &dapm->widgets, list) { list_for_each_entry(w, &dapm->card->widgets, list) {
if (w->dapm != dapm)
continue;
if (!strcmp(w->name, pin)) if (!strcmp(w->name, pin))
return w->connected; return w->connected;
} }
@ -2260,7 +2285,9 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
{ {
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
list_for_each_entry(w, &dapm->widgets, list) { list_for_each_entry(w, &dapm->card->widgets, list) {
if (w->dapm != dapm)
continue;
if (!strcmp(w->name, pin)) { if (!strcmp(w->name, pin)) {
w->ignore_suspend = 1; w->ignore_suspend = 1;
return 0; return 0;
@ -2291,7 +2318,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
LIST_HEAD(down_list); LIST_HEAD(down_list);
int powerdown = 0; int powerdown = 0;
list_for_each_entry(w, &dapm->widgets, list) { list_for_each_entry(w, &dapm->card->widgets, list) {
if (w->dapm != dapm)
continue;
if (w->power) { if (w->power) {
dapm_seq_insert(w, &down_list, dapm_down_seq); dapm_seq_insert(w, &down_list, dapm_down_seq);
w->power = 0; w->power = 0;