[alsa-devel] [PATCH v2 00/11] ASoC: Add support for DAPM at the component level
Changes since v1: * Rebased onto asoc/for-next and 3.16-rc1 * Added patch to remove platform field from widget and DAPM context to prevent new users from being added
Original cover letter:
Hi,
This series is the next step in componentization. It moves the DAPM support to the component level. This will allow any component to have DAPM widgets and routes, which was previously only possible for CODECs, and will allow any component to have DAPM widgets with controls (i.e. Mixers and MUXs), which was previously only possible for CODECs. At the end of this patchset the DAPM code will have (almost) no dependency on snd_soc_codec or snd_soc_platform and the dependency on snd_soc_component is confined to 4 small helper functions. The only reason why there is still snd_soc_codec/snd_soc_platform dependent code is because there are still a lot of drivers which use widget->codec/platform and dapm->codec/platform. So those still need to be initialized. This will be cleaned up in a separate series and once that's done the codec and platform fields will be removed from the widget and DAPM context struct.
One of the major problems of moving DAPM to the component level is that the DAPM context is directly embedded in the snd_soc_codec and snd_soc_platform structs and there are many drivers directly accessing that embedded field. This means it is not possible to move the field without causing a bit of code churn in the drivers. The patch series solves this by adding two fields to the component struct. One pointer to a DAPM context, which points to the DAPM context that is used by the component. And one DAPM context, which is used as the default if no other DAPM context was provided. Neither of the fields is accessed directly, instead a inline helper function is added that returns the DAPM context for a component. This will make it possible to eventually seamlessly switch over once all direct references to CODEC and platform DAPM contexts have been eliminated.
- Lars
Lars-Peter Clausen (11): ASoC: Move name_prefix from CODEC to component ASoC: Move name and id from CODEC/platform to component ASoC: Split component registration into two steps ASoC: Auto disconnect pins from all DAPM contexts ASoC: Add a set_bias_level() callback to the DAPM context struct ASoC: Add DAPM support at the component level ASoC: Use component DAPM context for platforms ASoC: Add component level stream_event() and seq_notifier() support ASoC: Add component level set_bias_level() support ASoC: dapm: Remove DAI DAPM context ASoC: dapm: Remove platform field from widget and dapm context struct
include/sound/soc-dai.h | 1 - include/sound/soc-dapm.h | 8 +- include/sound/soc.h | 53 +++++-- include/trace/events/asoc.h | 6 +- sound/soc/codecs/tlv320dac33.c | 2 +- sound/soc/soc-cache.c | 7 +- sound/soc/soc-compress.c | 8 +- sound/soc/soc-core.c | 330 +++++++++++++++++++++++------------------ sound/soc/soc-dapm.c | 183 +++++++++++++---------- sound/soc/soc-pcm.c | 4 +- 10 files changed, 344 insertions(+), 258 deletions(-)
Move the name_prefix from the CODEC struct to the component struct. This will eventually allow to specify prefixes for all types of components. It is also necessary to make the DAPM code component type independent (i.e. a DAPM context does not need to know whether it belongs to a CODEC or a platform or something else).
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc.h | 2 +- sound/soc/soc-core.c | 12 ++++++------ sound/soc/soc-dapm.c | 36 ++++++++++++++++++++++-------------- 3 files changed, 29 insertions(+), 21 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index ed9e2d7..e1cce00 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -682,6 +682,7 @@ struct snd_soc_component_driver { struct snd_soc_component { const char *name; int id; + const char *name_prefix; struct device *dev;
unsigned int active; @@ -710,7 +711,6 @@ struct snd_soc_component { /* SoC Audio Codec device */ struct snd_soc_codec { const char *name; - const char *name_prefix; int id; struct device *dev; const struct snd_soc_codec_driver *driver; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b87d7d8..ba822e9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1108,7 +1108,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) }
static void soc_set_name_prefix(struct snd_soc_card *card, - struct snd_soc_codec *codec) + struct snd_soc_component *component) { int i;
@@ -1117,11 +1117,11 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
for (i = 0; i < card->num_configs; i++) { struct snd_soc_codec_conf *map = &card->codec_conf[i]; - if (map->of_node && codec->dev->of_node != map->of_node) + if (map->of_node && component->dev->of_node != map->of_node) continue; - if (map->dev_name && strcmp(codec->name, map->dev_name)) + if (map->dev_name && strcmp(component->name, map->dev_name)) continue; - codec->name_prefix = map->name_prefix; + component->name_prefix = map->name_prefix; break; } } @@ -1135,7 +1135,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
codec->card = card; codec->dapm.card = card; - soc_set_name_prefix(card, codec); + soc_set_name_prefix(card, &codec->component);
if (!try_module_get(codec->dev->driver->owner)) return -ENODEV; @@ -2403,7 +2403,7 @@ int snd_soc_add_codec_controls(struct snd_soc_codec *codec, struct snd_card *card = codec->card->snd_card;
return snd_soc_add_controls(card, codec->dev, controls, num_controls, - codec->name_prefix, &codec->component); + codec->component.name_prefix, &codec->component); } EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index cdc837e..8e08ace 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -375,6 +375,13 @@ static void dapm_reset(struct snd_soc_card *card) } }
+static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm) +{ + if (!dapm->component) + return NULL; + return dapm->component->name_prefix; +} + static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, unsigned int *value) { @@ -570,11 +577,7 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, const char *name; int ret;
- if (dapm->codec) - prefix = dapm->codec->name_prefix; - else - prefix = NULL; - + prefix = soc_dapm_prefix(dapm); if (prefix) prefix_len = strlen(prefix) + 1; else @@ -2371,14 +2374,16 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, const char *source; char prefixed_sink[80]; char prefixed_source[80]; + const char *prefix; int ret;
- if (dapm->codec && dapm->codec->name_prefix) { + prefix = soc_dapm_prefix(dapm); + if (prefix) { snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", - dapm->codec->name_prefix, route->sink); + prefix, route->sink); sink = prefixed_sink; snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", - dapm->codec->name_prefix, route->source); + prefix, route->source); source = prefixed_source; } else { sink = route->sink; @@ -2439,6 +2444,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, const char *source; char prefixed_sink[80]; char prefixed_source[80]; + const char *prefix;
if (route->control) { dev_err(dapm->dev, @@ -2446,12 +2452,13 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, return -EINVAL; }
- if (dapm->codec && dapm->codec->name_prefix) { + prefix = soc_dapm_prefix(dapm); + if (prefix) { snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", - dapm->codec->name_prefix, route->sink); + prefix, route->sink); sink = prefixed_sink; snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", - dapm->codec->name_prefix, route->source); + prefix, route->source); source = prefixed_source; } else { sink = route->sink; @@ -2971,6 +2978,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget) { struct snd_soc_dapm_widget *w; + const char *prefix; int ret;
if ((w = dapm_cnew_widget(widget)) == NULL) @@ -3011,9 +3019,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, break; }
- if (dapm->codec && dapm->codec->name_prefix) - w->name = kasprintf(GFP_KERNEL, "%s %s", - dapm->codec->name_prefix, widget->name); + prefix = soc_dapm_prefix(dapm); + if (prefix) + w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); else w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
On Mon, Jun 16, 2014 at 06:13:01PM +0200, Lars-Peter Clausen wrote:
Move the name_prefix from the CODEC struct to the component struct. This will eventually allow to specify prefixes for all types of components. It is also necessary to make the DAPM code component type independent (i.e. a DAPM context does not need to know whether it belongs to a CODEC or a platform or something else).
Applied, thanks.
The component struct already has a name and id field which are initialized to the same values as the same fields in the CODEC and platform structs. So remove them from the CODEC and platform structs and used the ones from the component struct instead.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc.h | 4 ---- include/trace/events/asoc.h | 6 ++--- sound/soc/codecs/tlv320dac33.c | 2 +- sound/soc/soc-cache.c | 7 +++--- sound/soc/soc-compress.c | 8 ++++--- sound/soc/soc-core.c | 53 ++++++++++++++++-------------------------- sound/soc/soc-dapm.c | 8 +++---- sound/soc/soc-pcm.c | 4 ++-- 8 files changed, 38 insertions(+), 54 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index e1cce00..f64bf94 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -710,8 +710,6 @@ struct snd_soc_component {
/* SoC Audio Codec device */ struct snd_soc_codec { - const char *name; - int id; struct device *dev; const struct snd_soc_codec_driver *driver;
@@ -848,8 +846,6 @@ struct snd_soc_platform_driver { };
struct snd_soc_platform { - const char *name; - int id; struct device *dev; const struct snd_soc_platform_driver *driver;
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index c75c795..0194a64 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -296,17 +296,17 @@ TRACE_EVENT(snd_soc_cache_sync, TP_ARGS(codec, type, status),
TP_STRUCT__entry( - __string( name, codec->name ) + __string( name, codec->component.name) __string( status, status ) __string( type, type ) __field( int, id ) ),
TP_fast_assign( - __assign_str(name, codec->name); + __assign_str(name, codec->component.name); __assign_str(status, status); __assign_str(type, type); - __entry->id = codec->id; + __entry->id = codec->component.id; ),
TP_printk("codec=%s.%d type=%s status=%s", __get_str(name), diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index df3a750..ff006cc 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1404,7 +1404,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec) if (dac33->irq >= 0) { ret = request_irq(dac33->irq, dac33_interrupt_handler, IRQF_TRIGGER_RISING, - codec->name, codec); + codec->component.name, codec); if (ret < 0) { dev_err(codec->dev, "Could not request IRQ%d (%d)\n", dac33->irq, ret); diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 00e70b6..a9f82b5 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -78,7 +78,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) mutex_init(&codec->cache_rw_mutex);
dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", - codec->name); + codec->component.name);
if (codec_drv->reg_cache_default) codec->reg_cache = kmemdup(codec_drv->reg_cache_default, @@ -98,8 +98,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) int snd_soc_cache_exit(struct snd_soc_codec *codec) { dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", - codec->name); - + codec->component.name); kfree(codec->reg_cache); codec->reg_cache = NULL; return 0; @@ -192,7 +191,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec) return 0;
dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", - codec->name); + codec->component.name); trace_snd_soc_cache_sync(codec, name, "start"); ret = snd_soc_flat_cache_sync(codec); if (!ret) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 10f7f1d..f96fb96 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -37,7 +37,8 @@ static int soc_compr_open(struct snd_compr_stream *cstream) if (platform->driver->compr_ops && platform->driver->compr_ops->open) { ret = platform->driver->compr_ops->open(cstream); if (ret < 0) { - pr_err("compress asoc: can't open platform %s\n", platform->name); + pr_err("compress asoc: can't open platform %s\n", + platform->component.name); goto out; } } @@ -84,7 +85,8 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) if (platform->driver->compr_ops && platform->driver->compr_ops->open) { ret = platform->driver->compr_ops->open(cstream); if (ret < 0) { - pr_err("compress asoc: can't open platform %s\n", platform->name); + pr_err("compress asoc: can't open platform %s\n", + platform->component.name); goto out; } } @@ -680,7 +682,7 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); if (ret < 0) { pr_err("compress asoc: can't create compress for codec %s\n", - codec->name); + codec->component.name); goto compr_err; }
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ba822e9..b8cc88a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -274,7 +274,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) { struct dentry *debugfs_card_root = codec->card->debugfs_card_root;
- codec->debugfs_codec_root = debugfs_create_dir(codec->name, + codec->debugfs_codec_root = debugfs_create_dir(codec->component.name, debugfs_card_root); if (!codec->debugfs_codec_root) { dev_warn(codec->dev, @@ -306,8 +306,8 @@ static void soc_init_platform_debugfs(struct snd_soc_platform *platform) { struct dentry *debugfs_card_root = platform->card->debugfs_card_root;
- platform->debugfs_platform_root = debugfs_create_dir(platform->name, - debugfs_card_root); + platform->debugfs_platform_root = debugfs_create_dir( + platform->component.name, debugfs_card_root); if (!platform->debugfs_platform_root) { dev_warn(platform->dev, "ASoC: Failed to create platform debugfs directory\n"); @@ -335,7 +335,7 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
list_for_each_entry(codec, &codec_list, list) { len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", - codec->name); + codec->component.name); if (len >= 0) ret += len; if (ret > PAGE_SIZE) { @@ -406,7 +406,7 @@ static ssize_t platform_list_read_file(struct file *file,
list_for_each_entry(platform, &platform_list, list) { len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", - platform->name); + platform->component.name); if (len >= 0) ret += len; if (ret > PAGE_SIZE) { @@ -528,7 +528,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) codec->ac97->dev.release = soc_ac97_device_release;
dev_set_name(&codec->ac97->dev, "%d-%d:%s", - codec->card->snd_card->number, 0, codec->name); + codec->card->snd_card->number, 0, codec->component.name); err = device_register(&codec->ac97->dev); if (err < 0) { dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); @@ -857,7 +857,7 @@ static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_n if (codec->dev->of_node != codec_of_node) continue; } else { - if (strcmp(codec->name, codec_name)) + if (strcmp(codec->component.name, codec_name)) continue; }
@@ -945,7 +945,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) dai_link->platform_of_node) continue; } else { - if (strcmp(platform->name, platform_name)) + if (strcmp(platform->component.name, platform_name)) continue; }
@@ -1177,7 +1177,7 @@ static int soc_probe_codec(struct snd_soc_card *card, WARN(codec->dapm.idle_bias_off && codec->dapm.bias_level != SND_SOC_BIAS_OFF, "codec %s can not start from non-off bias with idle_bias_off==1\n", - codec->name); + codec->component.name); }
if (driver->controls) @@ -1647,7 +1647,8 @@ static struct snd_soc_codec *soc_find_matching_codec(struct snd_soc_card *card, if (aux_dev->codec_of_node && (codec->dev->of_node != aux_dev->codec_of_node)) continue; - if (aux_dev->codec_name && strcmp(codec->name, aux_dev->codec_name)) + if (aux_dev->codec_name && + strcmp(codec->component.name, aux_dev->codec_name)) continue; return codec; } @@ -4131,11 +4132,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, { int ret;
- /* create platform component name */ - platform->name = fmt_single_name(dev, &platform->id); - if (platform->name == NULL) - return -ENOMEM; - platform->dev = dev; platform->driver = platform_drv; platform->dapm.dev = dev; @@ -4161,7 +4157,8 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, list_add(&platform->list, &platform_list); mutex_unlock(&client_mutex);
- dev_dbg(dev, "ASoC: Registered platform '%s'\n", platform->name); + dev_dbg(dev, "ASoC: Registered platform '%s'\n", + platform->component.name);
return 0; } @@ -4205,8 +4202,7 @@ void snd_soc_remove_platform(struct snd_soc_platform *platform) mutex_unlock(&client_mutex);
dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n", - platform->name); - kfree(platform->name); + platform->component.name); } EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
@@ -4312,13 +4308,6 @@ int snd_soc_register_codec(struct device *dev, if (codec == NULL) return -ENOMEM;
- /* create CODEC component name */ - codec->name = fmt_single_name(dev, &codec->id); - if (codec->name == NULL) { - ret = -ENOMEM; - goto fail_codec; - } - if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) @@ -4368,19 +4357,17 @@ int snd_soc_register_codec(struct device *dev, codec, dai_drv, num_dai, false); if (ret < 0) { dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); - goto fail_codec_name; + goto fail_codec; }
- dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name); + dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", + codec->component.name); return 0;
-fail_codec_name: +fail_codec: mutex_lock(&client_mutex); list_del(&codec->list); mutex_unlock(&client_mutex); - - kfree(codec->name); -fail_codec: kfree(codec); return ret; } @@ -4408,10 +4395,10 @@ found: list_del(&codec->list); mutex_unlock(&client_mutex);
- dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name); + dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", + codec->component.name);
snd_soc_cache_exit(codec); - kfree(codec->name); kfree(codec); } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8e08ace..f3ccf6d1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3403,8 +3403,8 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) source = cpu_dai->playback_widget; sink = codec_dai->playback_widget; dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - cpu_dai->codec->name, source->name, - codec_dai->platform->name, sink->name); + cpu_dai->component->name, source->name, + codec_dai->component->name, sink->name);
snd_soc_dapm_add_path(&card->dapm, source, sink, NULL, NULL); @@ -3415,8 +3415,8 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) source = codec_dai->capture_widget; sink = cpu_dai->capture_widget; dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - codec_dai->codec->name, source->name, - cpu_dai->platform->name, sink->name); + codec_dai->component->name, source->name, + cpu_dai->component->name, sink->name);
snd_soc_dapm_add_path(&card->dapm, source, sink, NULL, NULL); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 54d18f2..9b78bb6 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -376,7 +376,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ret = platform->driver->ops->open(substream); if (ret < 0) { dev_err(platform->dev, "ASoC: can't open platform" - " %s: %d\n", platform->name, ret); + " %s: %d\n", platform->component.name, ret); goto platform_err; } } @@ -707,7 +707,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ret = platform->driver->ops->hw_params(substream, params); if (ret < 0) { dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", - platform->name, ret); + platform->component.name, ret); goto platform_err; } }
On Mon, Jun 16, 2014 at 06:13:02PM +0200, Lars-Peter Clausen wrote:
The component struct already has a name and id field which are initialized to the same values as the same fields in the CODEC and platform structs. So remove them from the CODEC and platform structs and used the ones from the component struct instead.
Applied, thanks.
Split snd_soc_component_register() into snd_soc_component_initialize() and snd_soc_component_add(). Using a 2-stage registration approach has the advantage that it is possible to modify the component after it has been initialized, but before it is made visible to the system. This e.g. allows CODECs or platforms to overwrite some of the default settings made in snd_soc_component_initialize().
Similar snd_soc_component_unregister() is split into two steps as well, snd_soc_component_delete(), which removes the component from the system, and snd_soc_component_cleanup(), which frees all the resources allocated by the component.
Furthermore this patch makes sure that if a component is visible on two list (e.g. the component list and the CODEC list) it is added or removed to both lists atomically.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/soc-core.c | 177 ++++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 86 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b8cc88a..0944da6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3922,16 +3922,14 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) * snd_soc_register_dais - Register a DAI with the ASoC core * * @component: The component the DAIs are registered for - * @codec: The CODEC that the DAIs are registered for, NULL if the component is - * not a CODEC. * @dai_drv: DAI driver to use for the DAIs * @count: Number of DAIs * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the * parent's name. */ static int snd_soc_register_dais(struct snd_soc_component *component, - struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, - size_t count, bool legacy_dai_naming) + struct snd_soc_dai_driver *dai_drv, size_t count, + bool legacy_dai_naming) { struct device *dev = component->dev; struct snd_soc_dai *dai; @@ -3940,6 +3938,9 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
+ component->dai_drv = dai_drv; + component->num_dai = count; + for (i = 0; i < count; i++) {
dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); @@ -3972,7 +3973,6 @@ static int snd_soc_register_dais(struct snd_soc_component *component, }
dai->component = component; - dai->codec = codec; dai->dev = dev; dai->driver = &dai_drv[i]; dai->dapm.dev = dev; @@ -3995,60 +3995,52 @@ err: return ret; }
-/** - * snd_soc_register_component - Register a component with the ASoC core - * - */ -static int -__snd_soc_register_component(struct device *dev, - struct snd_soc_component *cmpnt, - const struct snd_soc_component_driver *cmpnt_drv, - struct snd_soc_codec *codec, - struct snd_soc_dai_driver *dai_drv, - int num_dai, bool allow_single_dai) +static int snd_soc_component_initialize(struct snd_soc_component *component, + const struct snd_soc_component_driver *driver, struct device *dev) { - int ret; - - dev_dbg(dev, "component register %s\n", dev_name(dev)); - - if (!cmpnt) { - dev_err(dev, "ASoC: Failed to connecting component\n"); + component->name = fmt_single_name(dev, &component->id); + if (!component->name) { + dev_err(dev, "ASoC: Failed to allocate name\n"); return -ENOMEM; }
- mutex_init(&cmpnt->io_mutex); + component->dev = dev; + component->driver = driver;
- cmpnt->name = fmt_single_name(dev, &cmpnt->id); - if (!cmpnt->name) { - dev_err(dev, "ASoC: Failed to simplifying name\n"); - return -ENOMEM; - } + INIT_LIST_HEAD(&component->dai_list); + mutex_init(&component->io_mutex);
- cmpnt->dev = dev; - cmpnt->driver = cmpnt_drv; - cmpnt->dai_drv = dai_drv; - cmpnt->num_dai = num_dai; - INIT_LIST_HEAD(&cmpnt->dai_list); + return 0; +}
- ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai, - allow_single_dai); - if (ret < 0) { - dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); - goto error_component_name; - } +static void snd_soc_component_add_unlocked(struct snd_soc_component *component) +{ + list_add(&component->list, &component_list); +}
+static void snd_soc_component_add(struct snd_soc_component *component) +{ mutex_lock(&client_mutex); - list_add(&cmpnt->list, &component_list); + snd_soc_component_add_unlocked(component); mutex_unlock(&client_mutex); +}
- dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); - - return ret; +static void snd_soc_component_cleanup(struct snd_soc_component *component) +{ + snd_soc_unregister_dais(component); + kfree(component->name); +}
-error_component_name: - kfree(cmpnt->name); +static void snd_soc_component_del_unlocked(struct snd_soc_component *component) +{ + list_del(&component->list); +}
- return ret; +static void snd_soc_component_del(struct snd_soc_component *component) +{ + mutex_lock(&client_mutex); + snd_soc_component_del_unlocked(component); + mutex_unlock(&client_mutex); }
int snd_soc_register_component(struct device *dev, @@ -4057,32 +4049,38 @@ int snd_soc_register_component(struct device *dev, int num_dai) { struct snd_soc_component *cmpnt; + int ret;
- cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); + cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL); if (!cmpnt) { dev_err(dev, "ASoC: Failed to allocate memory\n"); return -ENOMEM; }
+ ret = snd_soc_component_initialize(cmpnt, cmpnt_drv, dev); + if (ret) + goto err_free; + cmpnt->ignore_pmdown_time = true; cmpnt->registered_as_component = true;
- return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, - dai_drv, num_dai, true); -} -EXPORT_SYMBOL_GPL(snd_soc_register_component); + ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto err_cleanup; + }
-static void __snd_soc_unregister_component(struct snd_soc_component *cmpnt) -{ - snd_soc_unregister_dais(cmpnt); + snd_soc_component_add(cmpnt);
- mutex_lock(&client_mutex); - list_del(&cmpnt->list); - mutex_unlock(&client_mutex); + return 0;
- dev_dbg(cmpnt->dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); - kfree(cmpnt->name); +err_cleanup: + snd_soc_component_cleanup(cmpnt); +err_free: + kfree(cmpnt); + return ret; } +EXPORT_SYMBOL_GPL(snd_soc_register_component);
/** * snd_soc_unregister_component - Unregister a component from the ASoC core @@ -4099,7 +4097,9 @@ void snd_soc_unregister_component(struct device *dev) return;
found: - __snd_soc_unregister_component(cmpnt); + snd_soc_component_del(cmpnt); + snd_soc_component_cleanup(cmpnt); + kfree(cmpnt); } EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
@@ -4132,6 +4132,11 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, { int ret;
+ ret = snd_soc_component_initialize(&platform->component, + &platform_drv->component_driver, dev); + if (ret) + return ret; + platform->dev = dev; platform->driver = platform_drv; platform->dapm.dev = dev; @@ -4143,17 +4148,8 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, if (platform_drv->read) platform->component.read = snd_soc_platform_drv_read;
- /* register component */ - ret = __snd_soc_register_component(dev, &platform->component, - &platform_drv->component_driver, - NULL, NULL, 0, false); - if (ret < 0) { - dev_err(platform->component.dev, - "ASoC: Failed to register component: %d\n", ret); - return ret; - } - mutex_lock(&client_mutex); + snd_soc_component_add_unlocked(&platform->component); list_add(&platform->list, &platform_list); mutex_unlock(&client_mutex);
@@ -4195,12 +4191,14 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform); */ void snd_soc_remove_platform(struct snd_soc_platform *platform) { - __snd_soc_unregister_component(&platform->component);
mutex_lock(&client_mutex); list_del(&platform->list); + snd_soc_component_del_unlocked(&platform->component); mutex_unlock(&client_mutex);
+ snd_soc_component_cleanup(&platform->component); + dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n", platform->component.name); } @@ -4299,6 +4297,7 @@ int snd_soc_register_codec(struct device *dev, int num_dai) { struct snd_soc_codec *codec; + struct snd_soc_dai *dai; struct regmap *regmap; int ret, i;
@@ -4308,6 +4307,11 @@ int snd_soc_register_codec(struct device *dev, if (codec == NULL) return -ENOMEM;
+ ret = snd_soc_component_initialize(&codec->component, + &codec_drv->component_driver, dev); + if (ret) + goto err_free; + if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) @@ -4337,7 +4341,7 @@ int snd_soc_register_codec(struct device *dev, dev_err(codec->dev, "Failed to set cache I/O:%d\n", ret); - return ret; + goto err_cleanup; } } } @@ -4347,27 +4351,27 @@ int snd_soc_register_codec(struct device *dev, fixup_codec_formats(&dai_drv[i].capture); }
+ ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto err_cleanup; + } + + list_for_each_entry(dai, &codec->component.dai_list, list) + dai->codec = codec; + mutex_lock(&client_mutex); + snd_soc_component_add_unlocked(&codec->component); list_add(&codec->list, &codec_list); mutex_unlock(&client_mutex);
- /* register component */ - ret = __snd_soc_register_component(dev, &codec->component, - &codec_drv->component_driver, - codec, dai_drv, num_dai, false); - if (ret < 0) { - dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); - goto fail_codec; - } - dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->component.name); return 0;
-fail_codec: - mutex_lock(&client_mutex); - list_del(&codec->list); - mutex_unlock(&client_mutex); +err_cleanup: + snd_soc_component_cleanup(&codec->component); +err_free: kfree(codec); return ret; } @@ -4389,15 +4393,16 @@ void snd_soc_unregister_codec(struct device *dev) return;
found: - __snd_soc_unregister_component(&codec->component);
mutex_lock(&client_mutex); list_del(&codec->list); + snd_soc_component_del_unlocked(&codec->component); mutex_unlock(&client_mutex);
dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->component.name);
+ snd_soc_component_cleanup(&codec->component); snd_soc_cache_exit(codec); kfree(codec); }
On Mon, Jun 16, 2014 at 06:13:03PM +0200, Lars-Peter Clausen wrote:
Split snd_soc_component_register() into snd_soc_component_initialize() and snd_soc_component_add(). Using a 2-stage registration approach has the advantage that it is possible to modify the component after it has been initialized, but before it is made visible to the system. This e.g. allows CODECs or platforms to overwrite some of the default settings made in snd_soc_component_initialize().
Applied, thanks.
Currently only pins in CODEC DAPM contexts are automatically marked as non-connected if the card has the fully_routed flag set. This makes sense since widgets which qualify for auto-disconnection are only found in CODEC DAPM contexts. But with componentisation this is going to change, so consider all widgets for auto-disconnection.
Also it is probably faster to walk the widgets list only once rather than once for each CODEC.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dapm.h | 2 +- sound/soc/soc-core.c | 3 +-- sound/soc/soc-dapm.c | 27 +++++++++++---------------- 3 files changed, 13 insertions(+), 19 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 6b59471..8db627c 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -431,7 +431,7 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); -void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec); +void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
/* Mostly internal - should not normally be used */ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0944da6..bca8a71 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1928,8 +1928,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) }
if (card->fully_routed) - list_for_each_entry(codec, &card->codec_dev_list, card_list) - snd_soc_dapm_auto_nc_codec_pins(codec); + snd_soc_dapm_auto_nc_pins(card);
snd_soc_dapm_new_widgets(card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f3ccf6d1..fab1a88 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3766,36 +3766,31 @@ static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, }
/** - * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins - * @codec: The codec whose pins should be processed + * snd_soc_dapm_auto_nc_pins - call snd_soc_dapm_nc_pin for unused pins + * @card: The card whose pins should be processed * - * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec - * which are unused. Pins are used if they are connected externally to the - * codec, whether that be to some other device, or a loop-back connection to - * the codec itself. + * Automatically call snd_soc_dapm_nc_pin() for any external pins in the card + * which are unused. Pins are used if they are connected externally to a + * component, whether that be to some other device, or a loop-back connection to + * the component itself. */ -void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec) +void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card) { - struct snd_soc_card *card = codec->card; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_widget *w;
- dev_dbg(codec->dev, "ASoC: Auto NC: DAPMs: card:%p codec:%p\n", - &card->dapm, &codec->dapm); + dev_dbg(card->dev, "ASoC: Auto NC: DAPMs: card:%p\n", &card->dapm);
list_for_each_entry(w, &card->widgets, list) { - if (w->dapm != dapm) - continue; switch (w->id) { case snd_soc_dapm_input: case snd_soc_dapm_output: case snd_soc_dapm_micbias: - dev_dbg(codec->dev, "ASoC: Auto NC: Checking widget %s\n", + dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n", w->name); if (!snd_soc_dapm_widget_in_card_paths(card, w)) { - dev_dbg(codec->dev, + dev_dbg(card->dev, "... Not in map; disabling\n"); - snd_soc_dapm_nc_pin(dapm, w->name); + snd_soc_dapm_nc_pin(w->dapm, w->name); } break; default:
On Mon, Jun 16, 2014 at 06:13:04PM +0200, Lars-Peter Clausen wrote:
Currently only pins in CODEC DAPM contexts are automatically marked as non-connected if the card has the fully_routed flag set. This makes sense since widgets which qualify for auto-disconnection are only found in CODEC DAPM contexts. But with componentisation this is going to change, so consider all widgets for auto-disconnection.
Applied, thanks.
Currently the DAPM code directly looks at the CODEC driver struct to get a handle to the set_bias_level() callback. This patch adds a new set_bias_level() callback to the DAPM context struct. The DAPM code will use this new callback instead of the CODEC callback. For CODECs the new callback is set up to call the CODEC specific set_bias_level callback(). Not looking directly at the CODEC driver struct will allow non CODEC DAPM contexts to implement a set_bias_level() callback.
This is also similar to how the seq_notifier() and stream_event() callbacks are currently handled.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dapm.h | 2 ++ sound/soc/soc-core.c | 10 ++++++++++ sound/soc/soc-dapm.c | 11 +++-------- 3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 8db627c..3a5c4f9 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -601,6 +601,8 @@ struct snd_soc_dapm_context { struct list_head list;
int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); + int (*set_bias_level)(struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level);
#ifdef CONFIG_DEBUG_FS struct dentry *debugfs_dapm; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bca8a71..10e13c4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4285,6 +4285,14 @@ static int snd_soc_codec_drv_read(struct snd_soc_component *component, return 0; }
+static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); + + return codec->driver->set_bias_level(codec, level); +} + /** * snd_soc_register_codec - Register a codec with the ASoC core * @@ -4322,6 +4330,8 @@ int snd_soc_register_codec(struct device *dev, codec->dapm.component = &codec->component; codec->dapm.seq_notifier = codec_drv->seq_notifier; codec->dapm.stream_event = codec_drv->stream_event; + if (codec_drv->set_bias_level) + codec->dapm.set_bias_level = snd_soc_codec_set_bias_level; codec->dev = dev; codec->driver = codec_drv; codec->component.val_bytes = codec_drv->reg_word_size; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index fab1a88..6c94a6b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -427,15 +427,10 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, if (ret != 0) goto out;
- if (dapm->codec) { - if (dapm->codec->driver->set_bias_level) - ret = dapm->codec->driver->set_bias_level(dapm->codec, - level); - else - dapm->bias_level = level; - } else if (!card || dapm != &card->dapm) { + if (dapm->set_bias_level) + ret = dapm->set_bias_level(dapm, level); + else if (!card || dapm != &card->dapm) dapm->bias_level = level; - }
if (ret != 0) goto out;
On Mon, Jun 16, 2014 at 06:13:05PM +0200, Lars-Peter Clausen wrote:
CODEC specific set_bias_level callback(). Not looking directly at the CODEC driver struct will allow non CODEC DAPM contexts to implement a set_bias_level() callback.
It will indeed, but do we want them to? set_bias_level() is partly legacy and partly there for the benefit of analogue devices which can have more complex needs than digital ones which can mostly just use runtime PM. On the other hand there's a consistency thing going on here, but that applies both within ASoC and throughout the kernel.
On Sat, Jun 21, 2014 at 09:14:37PM +0100, Mark Brown wrote:
On Mon, Jun 16, 2014 at 06:13:05PM +0200, Lars-Peter Clausen wrote:
CODEC specific set_bias_level callback(). Not looking directly at the CODEC driver struct will allow non CODEC DAPM contexts to implement a set_bias_level() callback.
It will indeed, but do we want them to? set_bias_level() is partly legacy and partly there for the benefit of analogue devices which can have more complex needs than digital ones which can mostly just use runtime PM. On the other hand there's a consistency thing going on here, but that applies both within ASoC and throughout the kernel.
I think it would help :)
Even on DSPs loading firmware and power sequencing the DSP can get some help using these functions
I think I might find some use of this for my work!
On Sun, Jun 22, 2014 at 10:56:00AM +0530, Vinod Koul wrote:
Even on DSPs loading firmware and power sequencing the DSP can get some help using these functions
I think I might find some use of this for my work!
Please be more specific about this - what do they offer that runtime PM and widgets don't offer?
On Sun, Jun 22, 2014 at 11:12:36AM +0100, Mark Brown wrote:
On Sun, Jun 22, 2014 at 10:56:00AM +0530, Vinod Koul wrote:
Even on DSPs loading firmware and power sequencing the DSP can get some help using these functions
I think I might find some use of this for my work!
Please be more specific about this - what do they offer that runtime PM and widgets don't offer?
Well you are assuming that folks writing DSP FW will not have some wiered sequence!
Neverthless, i can think of two scenarios to control fw loading and sequences:
1. DMICs attached to DSP doing record but data getting consumed by DSP. No data goes to host cpu. No PCM/parameters here, so we can do a simple Input-Output loop. Somthing reverse of what we can do with Codec vibra. Widgets will not tell me when to load DSP FW. Since no device handle, no runtime here!
2. SoC DSP generating clock for codec and audio ICs even when no data is generated by SoC. This is not true for I2S but for other bus prtocols like Slimbus.
Thanks
On Mon, Jun 23, 2014 at 10:04:05AM +0530, Vinod Koul wrote:
On Sun, Jun 22, 2014 at 11:12:36AM +0100, Mark Brown wrote:
Please be more specific about this - what do they offer that runtime PM and widgets don't offer?
Well you are assuming that folks writing DSP FW will not have some wiered sequence!
Neverthless, i can think of two scenarios to control fw loading and sequences:
- DMICs attached to DSP doing record but data getting consumed by DSP. No data
goes to host cpu. No PCM/parameters here, so we can do a simple Input-Output loop. Somthing reverse of what we can do with Codec vibra. Widgets will not tell me when to load DSP FW. Since no device handle, no runtime here!
Why not? If there's a DAPM context there must be a struct device for it and if there's an audio path there should be widgets on it.
- SoC DSP generating clock for codec and audio ICs even when no data is
generated by SoC. This is not true for I2S but for other bus prtocols like Slimbus.
This sounds like something runtime PM would work fine for?
On Mon, Jun 16, 2014 at 06:13:05PM +0200, Lars-Peter Clausen wrote:
Currently the DAPM code directly looks at the CODEC driver struct to get a handle to the set_bias_level() callback. This patch adds a new set_bias_level() callback to the DAPM context struct. The DAPM code will use this new callback instead of the CODEC callback. For CODECs the new callback is set up to call the CODEC specific set_bias_level callback(). Not looking directly at the CODEC driver struct will allow non CODEC DAPM contexts to implement a set_bias_level() callback.
Applied, thanks.
This patch adds full DAPM support at the component level. Previously there was only full DAPM support for CODECs and partial DAPM support (e.g. no Mixers nor MUXs) for platforms. Having DAPM support at the component level will allow all types of components to use DAPM and also help in consolidating the DAPM support between CODECs and platforms.
Since the DAPM context is directly embedded into the snd_soc_codec and snd_soc_platform struct and the 'dapm' field is directly referenced in a lot of drivers moving the field just right now is not possible without causing code churn. The approach this patch takes is to add two new fields to the component struct. One field which is the pointer to the actual DAPM context used by the component and one DAPM context that will be used as the default if no other context was specified. For CODECs and platforms the pointer is initialized to point to the CODEC or platform DAPM context. All generic code when referencing a component's DAPM struct will go via the pointer. This will make it possible to eventually seamlessly move the DAPM context from snd_soc_codec and snd_soc_platform struct over once all direct references have been eliminated.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dapm.h | 2 + include/sound/soc.h | 30 ++++++++++++++ sound/soc/soc-core.c | 19 ++++++--- sound/soc/soc-dapm.c | 100 ++++++++++++++++++++++++++++++----------------- 4 files changed, 110 insertions(+), 41 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 3a5c4f9..e292683 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -441,6 +441,8 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, struct snd_soc_dapm_widget_list **list);
struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol); +struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( + struct snd_kcontrol *kcontrol);
/* dapm widget types */ enum snd_soc_dapm_type { diff --git a/include/sound/soc.h b/include/sound/soc.h index f64bf94..a21dfec 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -706,6 +706,10 @@ struct snd_soc_component { int val_bytes;
struct mutex io_mutex; + + /* Don't use these, use snd_soc_component_get_dapm() */ + struct snd_soc_dapm_context dapm; + struct snd_soc_dapm_context *dapm_ptr; };
/* SoC Audio Codec device */ @@ -1161,6 +1165,21 @@ static inline struct snd_soc_platform *snd_soc_component_to_platform( }
/** + * snd_soc_dapm_to_component() - Casts a DAPM context to the component it is + * embedded in + * @dapm: The DAPM context to cast to the component + * + * This function must only be used on DAPM contexts that are known to be part of + * a component (e.g. in a component driver). Otherwise the behavior is + * undefined. + */ +static inline struct snd_soc_component *snd_soc_dapm_to_component( + struct snd_soc_dapm_context *dapm) +{ + return container_of(dapm, struct snd_soc_component, dapm); +} + +/** * snd_soc_dapm_to_codec() - Casts a DAPM context to the CODEC it is embedded in * @dapm: The DAPM context to cast to the CODEC * @@ -1187,6 +1206,17 @@ static inline struct snd_soc_platform *snd_soc_dapm_to_platform( return container_of(dapm, struct snd_soc_platform, dapm); }
+/** + * snd_soc_component_get_dapm() - Returns the DAPM context associated with a + * component + * @component: The component for which to get the DAPM context + */ +static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( + struct snd_soc_component *component) +{ + return component->dapm_ptr; +} + /* codec IO */ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 10e13c4..f519a9f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3997,6 +3997,8 @@ err: static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { + struct snd_soc_dapm_context *dapm; + component->name = fmt_single_name(dev, &component->id); if (!component->name) { dev_err(dev, "ASoC: Failed to allocate name\n"); @@ -4006,6 +4008,14 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver;
+ if (!component->dapm_ptr) + component->dapm_ptr = &component->dapm; + + dapm = component->dapm_ptr; + dapm->dev = dev; + dapm->component = component; + dapm->bias_level = SND_SOC_BIAS_OFF; + INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex);
@@ -4131,6 +4141,8 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, { int ret;
+ platform->component.dapm_ptr = &platform->dapm; + ret = snd_soc_component_initialize(&platform->component, &platform_drv->component_driver, dev); if (ret) @@ -4138,9 +4150,7 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
platform->dev = dev; platform->driver = platform_drv; - platform->dapm.dev = dev; platform->dapm.platform = platform; - platform->dapm.component = &platform->component; platform->dapm.stream_event = platform_drv->stream_event; if (platform_drv->write) platform->component.write = snd_soc_platform_drv_write; @@ -4314,6 +4324,8 @@ int snd_soc_register_codec(struct device *dev, if (codec == NULL) return -ENOMEM;
+ codec->component.dapm_ptr = &codec->dapm; + ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev); if (ret) @@ -4324,10 +4336,7 @@ int snd_soc_register_codec(struct device *dev, if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; - codec->dapm.bias_level = SND_SOC_BIAS_OFF; - codec->dapm.dev = dev; codec->dapm.codec = codec; - codec->dapm.component = &codec->component; codec->dapm.seq_notifier = codec_drv->seq_notifier; codec->dapm.stream_event = codec_drv->stream_event; if (codec_drv->set_bias_level) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6c94a6b..4702b92 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -350,12 +350,27 @@ static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, }
/** + * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a + * kcontrol + * @kcontrol: The kcontrol + * + * Note: This function must only be used on kcontrols that are known to have + * been registered for a CODEC. Otherwise the behaviour is undefined. + */ +struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( + struct snd_kcontrol *kcontrol) +{ + return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm); + +/** * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol * @kcontrol: The kcontrol */ struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol) { - return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec; + return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol)); } EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
@@ -382,23 +397,31 @@ static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm) return dapm->component->name_prefix; }
-static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, +static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg, unsigned int *value) { - if (!w->dapm->component) + if (!dapm->component) return -EIO; - return snd_soc_component_read(w->dapm->component, reg, value); + return snd_soc_component_read(dapm->component, reg, value); }
-static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, +static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm, int reg, unsigned int mask, unsigned int value) { - if (!w->dapm->component) + if (!dapm->component) return -EIO; - return snd_soc_component_update_bits_async(w->dapm->component, reg, + return snd_soc_component_update_bits_async(dapm->component, reg, mask, value); }
+static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm, + int reg, unsigned int mask, unsigned int value) +{ + if (!dapm->component) + return -EIO; + return snd_soc_component_test_bits(dapm->component, reg, mask, value); +} + static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm) { if (dapm->component) @@ -454,7 +477,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, int i;
if (e->reg != SND_SOC_NOPM) { - soc_widget_read(dest, e->reg, &val); + soc_dapm_read(dapm, e->reg, &val); val = (val >> e->shift_l) & e->mask; item = snd_soc_enum_val_to_item(e, val); } else { @@ -498,7 +521,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, unsigned int val;
if (reg != SND_SOC_NOPM) { - soc_widget_read(w, reg, &val); + soc_dapm_read(w->dapm, reg, &val); val = (val >> shift) & mask; if (invert) val = max - val; @@ -1306,16 +1329,18 @@ static void dapm_seq_check_event(struct snd_soc_card *card, static void dapm_seq_run_coalesced(struct snd_soc_card *card, struct list_head *pending) { + struct snd_soc_dapm_context *dapm; struct snd_soc_dapm_widget *w; int reg; unsigned int value = 0; unsigned int mask = 0;
- reg = list_first_entry(pending, struct snd_soc_dapm_widget, - power_list)->reg; + w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list); + reg = w->reg; + dapm = w->dapm;
list_for_each_entry(w, pending, power_list) { - WARN_ON(reg != w->reg); + WARN_ON(reg != w->reg || dapm != w->dapm); w->power = w->new_power;
mask |= w->mask << w->shift; @@ -1324,7 +1349,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, else value |= w->off_val << w->shift;
- pop_dbg(w->dapm->dev, card->pop_time, + pop_dbg(dapm->dev, card->pop_time, "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", w->name, reg, value, mask);
@@ -1337,14 +1362,12 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card, /* Any widget will do, they should all be updating the * same register. */ - w = list_first_entry(pending, struct snd_soc_dapm_widget, - power_list);
- pop_dbg(w->dapm->dev, card->pop_time, + pop_dbg(dapm->dev, card->pop_time, "pop test : Applying 0x%x/0x%x to %x in %dms\n", value, mask, reg, card->pop_time); pop_wait(card->pop_time); - soc_widget_update_bits(w, reg, mask, value); + soc_dapm_update_bits(dapm, reg, mask, value); }
list_for_each_entry(w, pending, power_list) { @@ -1490,7 +1513,8 @@ static void dapm_widget_update(struct snd_soc_card *card) if (!w) return;
- ret = soc_widget_update_bits(w, update->reg, update->mask, update->val); + ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask, + update->val); if (ret < 0) dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", w->name, ret); @@ -2672,7 +2696,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
/* Read the initial power state from the device */ if (w->reg >= 0) { - soc_widget_read(w, w->reg, &val); + soc_dapm_read(w->dapm, w->reg, &val); val = val >> w->shift; val &= w->mask; if (val == w->on_val) @@ -2703,8 +2727,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); - struct snd_soc_card *card = codec->card; + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_card *card = dapm->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; @@ -2713,17 +2737,20 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; unsigned int val; + int ret = 0;
if (snd_soc_volsw_is_stereo(mc)) - dev_warn(codec->dapm.dev, + dev_warn(dapm->dev, "ASoC: Control '%s' is stereo, which is not supported\n", kcontrol->id.name);
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) - val = (snd_soc_read(codec, reg) >> shift) & mask; - else + if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) { + ret = soc_dapm_read(dapm, reg, &val); + val = (val >> shift) & mask; + } else { val = dapm_kcontrol_get_value(kcontrol); + } mutex_unlock(&card->dapm_mutex);
if (invert) @@ -2731,7 +2758,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, else ucontrol->value.integer.value[0] = val;
- return 0; + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
@@ -2747,8 +2774,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); - struct snd_soc_card *card = codec->card; + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_card *card = dapm->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; @@ -2762,7 +2789,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, int ret = 0;
if (snd_soc_volsw_is_stereo(mc)) - dev_warn(codec->dapm.dev, + dev_warn(dapm->dev, "ASoC: Control '%s' is stereo, which is not supported\n", kcontrol->id.name);
@@ -2780,7 +2807,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, mask = mask << shift; val = val << shift;
- reg_change = snd_soc_test_bits(codec, reg, mask, val); + reg_change = soc_dapm_test_bits(dapm, reg, mask, val); }
if (change || reg_change) { @@ -2819,12 +2846,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int reg_val, val; + int ret = 0;
if (e->reg != SND_SOC_NOPM) - reg_val = snd_soc_read(codec, e->reg); + ret = soc_dapm_read(dapm, e->reg, ®_val); else reg_val = dapm_kcontrol_get_value(kcontrol);
@@ -2836,7 +2864,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, ucontrol->value.enumerated.item[1] = val; }
- return 0; + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
@@ -2852,8 +2880,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); - struct snd_soc_card *card = codec->card; + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_card *card = dapm->card; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int *item = ucontrol->value.enumerated.item; unsigned int val, change; @@ -2876,7 +2904,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
if (e->reg != SND_SOC_NOPM) - change = snd_soc_test_bits(codec, e->reg, mask, val); + change = soc_dapm_test_bits(dapm, e->reg, mask, val); else change = dapm_kcontrol_set_value(kcontrol, val);
On Mon, Jun 16, 2014 at 06:13:06PM +0200, Lars-Peter Clausen wrote:
This patch adds full DAPM support at the component level. Previously there was only full DAPM support for CODECs and partial DAPM support (e.g. no Mixers nor MUXs) for platforms. Having DAPM support at the component level will allow all types of components to use DAPM and also help in consolidating the DAPM support between CODECs and platforms.
Applied, thanks.
The snd_soc_platform dapm field is not accessed outside of the ASoC core. Switch it over to using the snd_soc_component DAPM context.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc.h | 4 +--- sound/soc/soc-core.c | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index a21dfec..84ebc07 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -862,8 +862,6 @@ struct snd_soc_platform {
struct snd_soc_component component;
- struct snd_soc_dapm_context dapm; - #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_platform_root; #endif @@ -1203,7 +1201,7 @@ static inline struct snd_soc_codec *snd_soc_dapm_to_codec( static inline struct snd_soc_platform *snd_soc_dapm_to_platform( struct snd_soc_dapm_context *dapm) { - return container_of(dapm, struct snd_soc_platform, dapm); + return snd_soc_component_to_platform(snd_soc_dapm_to_component(dapm)); }
/** diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f519a9f..711e99c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -314,7 +314,7 @@ static void soc_init_platform_debugfs(struct snd_soc_platform *platform) return; }
- snd_soc_dapm_debugfs_init(&platform->dapm, + snd_soc_dapm_debugfs_init(&platform->component.dapm, platform->debugfs_platform_root); }
@@ -974,7 +974,7 @@ static int soc_remove_platform(struct snd_soc_platform *platform) }
/* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&platform->dapm); + snd_soc_dapm_free(&platform->component.dapm);
soc_cleanup_platform_debugfs(platform); platform->probed = 0; @@ -1210,7 +1210,7 @@ static int soc_probe_platform(struct snd_soc_card *card, struct snd_soc_dai *dai;
platform->card = card; - platform->dapm.card = card; + platform->component.dapm.card = card;
if (!try_module_get(platform->dev->driver->owner)) return -ENODEV; @@ -1218,7 +1218,7 @@ static int soc_probe_platform(struct snd_soc_card *card, soc_init_platform_debugfs(platform);
if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&platform->dapm, + snd_soc_dapm_new_controls(&platform->component.dapm, driver->dapm_widgets, driver->num_dapm_widgets);
/* Create DAPM widgets for each DAI stream */ @@ -1226,10 +1226,11 @@ static int soc_probe_platform(struct snd_soc_card *card, if (component->dev != platform->dev) continue; list_for_each_entry(dai, &component->dai_list, list) - snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); + snd_soc_dapm_new_dai_widgets(&platform->component.dapm, + dai); }
- platform->dapm.idle_bias_off = 1; + platform->component.dapm.idle_bias_off = 1;
if (driver->probe) { ret = driver->probe(platform); @@ -1244,13 +1245,13 @@ static int soc_probe_platform(struct snd_soc_card *card, snd_soc_add_platform_controls(platform, driver->controls, driver->num_controls); if (driver->dapm_routes) - snd_soc_dapm_add_routes(&platform->dapm, driver->dapm_routes, - driver->num_dapm_routes); + snd_soc_dapm_add_routes(&platform->component.dapm, + driver->dapm_routes, driver->num_dapm_routes);
/* mark platform as probed and add to card platform list */ platform->probed = 1; list_add(&platform->card_list, &card->platform_dev_list); - list_add(&platform->dapm.list, &card->dapm_list); + list_add(&platform->component.dapm.list, &card->dapm_list);
return 0;
@@ -4141,8 +4142,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, { int ret;
- platform->component.dapm_ptr = &platform->dapm; - ret = snd_soc_component_initialize(&platform->component, &platform_drv->component_driver, dev); if (ret) @@ -4150,8 +4149,8 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
platform->dev = dev; platform->driver = platform_drv; - platform->dapm.platform = platform; - platform->dapm.stream_event = platform_drv->stream_event; + platform->component.dapm.platform = platform; + platform->component.dapm.stream_event = platform_drv->stream_event; if (platform_drv->write) platform->component.write = snd_soc_platform_drv_write; if (platform_drv->read)
On Mon, Jun 16, 2014 at 06:13:07PM +0200, Lars-Peter Clausen wrote:
The snd_soc_platform dapm field is not accessed outside of the ASoC core. Switch it over to using the snd_soc_component DAPM context.
Applied, thanks.
This patch adds stream_event() and seq_notifier() callbacks similar to those found in the snd_soc_codec_driver and snd_soc_platform driver struct to the snd_soc_component_driver struct. This is meant to unify the handling of these callbacks across different types of components and will eventually allow their removal from the CODEC and platfrom driver structs.
The new callbacks are slightly different from the old ones in that they take a snd_soc_component as a parameter rather than a snd_soc_dapm_context. This was done since otherwise casting from the DAPM context to the component would typically be the first thing to do in the callback. And the interface becomes slightly cleaner by passing a snd_soc_component to all callbacks in the snd_soc_component_driver struct.
The patch also already removes the stream_event() callback from the snd_soc_codec_driver and snd_soc_platform_driver structs as it is currently unused.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc.h | 9 +++------ sound/soc/soc-core.c | 25 ++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 84ebc07..9a5b4f6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -677,6 +677,9 @@ struct snd_soc_component_driver { int (*of_xlate_dai_name)(struct snd_soc_component *component, struct of_phandle_args *args, const char **dai_name); + void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, + int subseq); + int (*stream_event)(struct snd_soc_component *, int event); };
struct snd_soc_component { @@ -792,9 +795,6 @@ struct snd_soc_codec_driver { void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int);
- /* codec stream completion event */ - int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); - bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */
/* probe ordering - for components with runtime dependencies */ @@ -836,9 +836,6 @@ struct snd_soc_platform_driver { /* platform stream compress ops */ const struct snd_compr_ops *compr_ops;
- /* platform stream completion event */ - int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); - /* probe ordering - for components with runtime dependencies */ int probe_order; int remove_order; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 711e99c..5fe732f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3995,6 +3995,22 @@ err: return ret; }
+static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, + enum snd_soc_dapm_type type, int subseq) +{ + struct snd_soc_component *component = dapm->component; + + component->driver->seq_notifier(component, type, subseq); +} + +static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, + int event) +{ + struct snd_soc_component *component = dapm->component; + + return component->driver->stream_event(component, event); +} + static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { @@ -4016,6 +4032,10 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; + if (driver->seq_notifier) + dapm->seq_notifier = snd_soc_component_seq_notifier; + if (driver->stream_event) + dapm->stream_event = snd_soc_component_stream_event;
INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); @@ -4150,7 +4170,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->dev = dev; platform->driver = platform_drv; platform->component.dapm.platform = platform; - platform->component.dapm.stream_event = platform_drv->stream_event; if (platform_drv->write) platform->component.write = snd_soc_platform_drv_write; if (platform_drv->read) @@ -4336,8 +4355,8 @@ int snd_soc_register_codec(struct device *dev, codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.codec = codec; - codec->dapm.seq_notifier = codec_drv->seq_notifier; - codec->dapm.stream_event = codec_drv->stream_event; + if (codec_drv->seq_notifier) + codec->dapm.seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) codec->dapm.set_bias_level = snd_soc_codec_set_bias_level; codec->dev = dev;
On Mon, Jun 16, 2014 at 06:13:08PM +0200, Lars-Peter Clausen wrote:
This patch adds stream_event() and seq_notifier() callbacks similar to those found in the snd_soc_codec_driver and snd_soc_platform driver struct to the snd_soc_component_driver struct. This is meant to unify the handling of these callbacks across different types of components and will eventually allow their removal from the CODEC and platfrom driver structs.
Applied, thanks.
This patch adds a set_bias_level() callback to the snd_soc_component_driver struct similar to that found in the snd_soc_codec_driver struct. This will allow any component type and not just CODECs to implement such a callback.
The semantics of the component driver and CODEC driver set_bias_level() callbacks slightly differ. While the CODEC driver callback only takes the target bias level, the component driver callback takes both the current and the target bias level. Also for the component driver callback the current bias level will be automatically updated to the target bias level if the callback does not return an error, whereas with the CODEC bias level callback this has to be done in every callback by hand. The change in semantics was implement because the new semantics more closly match what drivers need. Most drivers are interested in both the current and the target bias level and all drivers update the current to the target bias level in case there is no error.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc.h | 4 ++++ sound/soc/soc-core.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 9a5b4f6..e560b6f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -680,6 +680,10 @@ struct snd_soc_component_driver { void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, int subseq); int (*stream_event)(struct snd_soc_component *, int event); + int (*set_bias_level)(struct snd_soc_component *component, + enum snd_soc_bias_level current_level, + enum snd_soc_bias_level target_level); + bool idle_bias_off; };
struct snd_soc_component { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5fe732f..a414689 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4011,6 +4011,20 @@ static int snd_soc_component_stream_event(struct snd_soc_dapm_context *dapm, return component->driver->stream_event(component, event); }
+static int snd_soc_component_set_bias_level(struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level target_level) +{ + struct snd_soc_component *component = dapm->component; + int ret; + + ret = component->driver->set_bias_level(component, dapm->bias_level, + target_level); + if (ret == 0) + dapm->bias_level = target_level; + + return ret; +} + static int snd_soc_component_initialize(struct snd_soc_component *component, const struct snd_soc_component_driver *driver, struct device *dev) { @@ -4032,10 +4046,13 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; + dapm->idle_bias_off = driver->idle_bias_off; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; + if (driver->set_bias_level) + dapm->set_bias_level = snd_soc_component_set_bias_level;
INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex);
On Mon, Jun 16, 2014 at 06:13:09PM +0200, Lars-Peter Clausen wrote:
This patch adds a set_bias_level() callback to the snd_soc_component_driver struct similar to that found in the snd_soc_codec_driver struct. This will allow any component type and not just CODECs to implement such a callback.
So, as I said on the previous patch I'm not 100% sure about this one. On balance I think the symmetry argument wins out so it should go in even if people ought not to be using it but I want to think it over a little more.
The DAI DAPM context was added in commit be09ad90 ("ASoC: core: Add platform DAI widget mapping") and the only user was removed again in commit ae10e7e8f ("ASoC: core: Only add platform DAI widgets once."). Now that we have a per component DAPM context it is unlikely that we'll need the DAI DAPM context again.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dai.h | 1 - sound/soc/soc-core.c | 12 +----------- 2 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 688f2ba..031be2a 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -257,7 +257,6 @@ struct snd_soc_dai {
struct snd_soc_dapm_widget *playback_widget; struct snd_soc_dapm_widget *capture_widget; - struct snd_soc_dapm_context dapm;
/* DAI DMA data */ void *playback_dma_data; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a414689..19dfa80 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1048,11 +1048,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) cpu_dai->name, err); } cpu_dai->probed = 0; - - if (!cpu_dai->codec) { - snd_soc_dapm_free(&cpu_dai->dapm); + if (!cpu_dai->codec) module_put(cpu_dai->dev->driver->owner); - } } }
@@ -1510,11 +1507,8 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (!cpu_dai->probed && cpu_dai->driver->probe_order == order) { if (!cpu_dai->codec) { - cpu_dai->dapm.card = card; if (!try_module_get(cpu_dai->dev->driver->owner)) return -ENODEV; - - list_add(&cpu_dai->dapm.list, &card->dapm_list); }
if (cpu_dai->driver->probe) { @@ -3975,13 +3969,9 @@ static int snd_soc_register_dais(struct snd_soc_component *component, dai->component = component; dai->dev = dev; dai->driver = &dai_drv[i]; - dai->dapm.dev = dev; if (!dai->driver->ops) dai->driver->ops = &null_dai_ops;
- if (!dai->codec) - dai->dapm.idle_bias_off = 1; - list_add(&dai->list, &component->dai_list);
dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
On Mon, Jun 16, 2014 at 06:13:10PM +0200, Lars-Peter Clausen wrote:
The DAI DAPM context was added in commit be09ad90 ("ASoC: core: Add platform DAI widget mapping") and the only user was removed again in commit ae10e7e8f ("ASoC: core: Only add platform DAI widgets once."). Now that we have a per component DAPM context it is unlikely that we'll need the DAI DAPM context again.
Applied, thanks.
The platform field in the snd_soc_dapm_widget and snd_soc_dapm_context structs is now unused can be removed. New code that wants to get the platform for a widget or dapm context should use snd_soc_dapm_to_platform(w->dapm) or snd_soc_dapm_to_platform(dapm).
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dapm.h | 2 -- sound/soc/soc-core.c | 1 - sound/soc/soc-dapm.c | 1 - 3 files changed, 4 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index e292683..aac04ff 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -526,7 +526,6 @@ struct snd_soc_dapm_widget { const char *name; /* widget name */ const char *sname; /* stream name */ struct snd_soc_codec *codec; - struct snd_soc_platform *platform; struct list_head list; struct snd_soc_dapm_context *dapm;
@@ -595,7 +594,6 @@ struct snd_soc_dapm_context { struct device *dev; /* from parent - for debug */ struct snd_soc_component *component; /* parent component */ struct snd_soc_codec *codec; /* parent codec */ - struct snd_soc_platform *platform; /* parent platform */ struct snd_soc_card *card; /* parent card */
/* used during DAPM updates */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 19dfa80..7ad4838 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4176,7 +4176,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
platform->dev = dev; platform->driver = platform_drv; - platform->component.dapm.platform = platform; if (platform_drv->write) platform->component.write = snd_soc_platform_drv_write; if (platform_drv->read) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4702b92..4bf08cf 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3097,7 +3097,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
w->dapm = dapm; w->codec = dapm->codec; - w->platform = dapm->platform; INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list);
On Mon, Jun 16, 2014 at 06:13:11PM +0200, Lars-Peter Clausen wrote:
The platform field in the snd_soc_dapm_widget and snd_soc_dapm_context structs is now unused can be removed. New code that wants to get the platform for a widget or dapm context should use snd_soc_dapm_to_platform(w->dapm) or snd_soc_dapm_to_platform(dapm).
Applied, thanks.
participants (3)
-
Lars-Peter Clausen
-
Mark Brown
-
Vinod Koul