mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-11 21:14:07 +08:00
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:
parent
8ddab3f510
commit
97c866defc
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user