From c3753707991218aa2c18449a921847877533aa09 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Nov 2010 15:41:57 -0400 Subject: ASoC: Push snd_soc_write() and snd_soc_read() into the source file Facilitating adding trace type stuff. For a first pass add some dev_dbg() statements into them. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 614a8b30d87b..4360436ef035 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1877,6 +1877,25 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); +unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg) +{ + unsigned int ret; + + ret = codec->driver->read(codec, reg); + dev_dbg(codec->dev, "read %x => %x\n", reg, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_read); + +unsigned int snd_soc_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int val) +{ + dev_dbg(codec->dev, "write %x = %x\n", reg, val); + return codec->driver->write(codec, reg, val); +} +EXPORT_SYMBOL_GPL(snd_soc_write); + /** * snd_soc_update_bits - update codec register bits * @codec: audio codec -- cgit v1.2.3 From ce6120cca2589ede530200c7cfe11ac9f144333c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 5 Nov 2010 15:53:46 +0200 Subject: ASoC: Decouple DAPM from CODECs Decoupling Dynamic Audio Power Management (DAPM) from codec devices is required when developing ASoC further. Such as for other ASoC components to have DAPM widgets or when extending DAPM to handle cross-device paths. This patch decouples DAPM related variables from struct snd_soc_codec and moves them to new struct snd_soc_dapm_context that is used to encapsulate DAPM context of a device. ASoC core and API of DAPM functions are modified to use DAPM context instead of codec. This patch does not change current functionality and a large part of changes come because of structure and internal API changes. Core implementation is from Liam Girdwood with some minor core changes, codecs and machine driver conversions from Jarkko Nikula . Signed-off-by: Liam Girdwood Signed-off-by: Jarkko Nikula Cc: Nicolas Ferre Cc: Manuel Lauss Cc: Mike Frysinger Cc: Cliff Cai Cc: Kevin Hilman Cc: Ryan Mallon Cc: Timur Tabi Cc: Sascha Hauer Cc: Lars-Peter Clausen Cc: Arnaud Patard (Rtp) Cc: Wan ZongShun Cc: Eric Miao Cc: Jassi Brar Cc: Daniel Gloeckner Cc: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2198936cfb68..3c7c884f212c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -255,18 +255,18 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, codec->debugfs_codec_root, - &codec->pop_time); + &codec->dapm.pop_time); if (!codec->debugfs_pop_time) printk(KERN_WARNING "Failed to create pop time debugfs file\n"); - codec->debugfs_dapm = debugfs_create_dir("dapm", + codec->dapm.debugfs_dapm = debugfs_create_dir("dapm", codec->debugfs_codec_root); - if (!codec->debugfs_dapm) + if (!codec->dapm.debugfs_dapm) printk(KERN_WARNING "Failed to create DAPM debugfs directory\n"); - snd_soc_dapm_debugfs_init(codec); + snd_soc_dapm_debugfs_init(&codec->dapm); } static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) @@ -1017,7 +1017,7 @@ static int soc_suspend(struct device *dev) /* close any waiting streams and save state */ for (i = 0; i < card->num_rtd; i++) { run_delayed_work(&card->rtd[i].delayed_work); - card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level; + card->rtd[i].codec->dapm.suspend_bias_level = card->rtd[i].codec->dapm.bias_level; } for (i = 0; i < card->num_rtd; i++) { @@ -1041,7 +1041,7 @@ static int soc_suspend(struct device *dev) /* If there are paths active then the CODEC will be held with * bias _ON and should not be suspended. */ if (!codec->suspended && codec->driver->suspend) { - switch (codec->bias_level) { + switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_OFF: codec->driver->suspend(codec, PMSG_SUSPEND); @@ -1110,7 +1110,7 @@ static void soc_resume_deferred(struct work_struct *work) * resume. Otherwise the suspend was suppressed. */ if (codec->driver->resume && codec->suspended) { - switch (codec->bias_level) { + switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_OFF: codec->driver->resume(codec); @@ -1346,7 +1346,7 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) } /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(codec); + snd_soc_dapm_free(&codec->dapm); soc_cleanup_codec_debugfs(codec); device_remove_file(&rtd->dev, &dev_attr_codec_reg); @@ -1470,8 +1470,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) } /* Make sure all DAPM widgets are instantiated */ - snd_soc_dapm_new_widgets(codec); - snd_soc_dapm_sync(codec); + snd_soc_dapm_new_widgets(&codec->dapm); + snd_soc_dapm_sync(&codec->dapm); /* register the rtd device */ rtd->dev.release = rtd_release; @@ -3238,6 +3238,12 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; } + INIT_LIST_HEAD(&codec->dapm.widgets); + INIT_LIST_HEAD(&codec->dapm.paths); + codec->dapm.bias_level = SND_SOC_BIAS_OFF; + codec->dapm.dev = dev; + codec->dapm.codec = codec; + /* allocate CODEC register cache */ if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { @@ -3257,11 +3263,8 @@ int snd_soc_register_codec(struct device *dev, codec->dev = dev; codec->driver = codec_drv; - codec->bias_level = SND_SOC_BIAS_OFF; codec->num_dai = num_dai; mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); -- cgit v1.2.3 From a6052154944c822993d04ca8f8d8926e8b73b749 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 5 Nov 2010 20:35:19 +0200 Subject: ASoC: Add sound card directory under debugfs/asoc/ There will be need to have sound card specific debugfs entries. This patch introduces a new debugfs/asoc/{card->name}/ directory but does not add yet any entries there. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3c7c884f212c..b0f635ccf176 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -374,6 +374,20 @@ static const struct file_operations platform_list_fops = { .llseek = default_llseek,/* read accesses f_pos */ }; +static void soc_init_card_debugfs(struct snd_soc_card *card) +{ + card->debugfs_card_root = debugfs_create_dir(card->name, + debugfs_root); + if (!card->debugfs_card_root) + dev_warn(card->dev, + "ASoC: Failed to create codec debugfs directory\n"); +} + +static void soc_cleanup_card_debugfs(struct snd_soc_card *card) +{ + debugfs_remove_recursive(card->debugfs_card_root); +} + #else static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) @@ -1667,6 +1681,8 @@ static int soc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&card->codec_dev_list); INIT_LIST_HEAD(&card->platform_dev_list); + soc_init_card_debugfs(card); + ret = snd_soc_register_card(card); if (ret != 0) { dev_err(&pdev->dev, "Failed to register card\n"); @@ -1694,6 +1710,8 @@ static int soc_remove(struct platform_device *pdev) for (i = 0; i < card->num_rtd; i++) soc_remove_dai_link(card, i); + soc_cleanup_card_debugfs(card); + /* remove the card */ if (card->remove) card->remove(pdev); -- cgit v1.2.3 From d6ce4cf3967dca78f967cd0bf70b175084885f40 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 5 Nov 2010 20:35:20 +0200 Subject: ASoC: Move codec debugfs directories under parent card directory Make use of sound card debugfs directory and move codec directories under the parent card debugfs directory. debugfs/asoc/{codec dir} -> debugfs/asoc/{card->name}/{codec dir}. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b0f635ccf176..57e5d7bfb130 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -238,8 +238,10 @@ static const struct file_operations codec_reg_fops = { static void soc_init_codec_debugfs(struct snd_soc_codec *codec) { - codec->debugfs_codec_root = debugfs_create_dir(codec->name , - debugfs_root); + struct dentry *debugfs_card_root = codec->card->debugfs_card_root; + + codec->debugfs_codec_root = debugfs_create_dir(codec->name, + debugfs_card_root); if (!codec->debugfs_codec_root) { printk(KERN_WARNING "ASoC: Failed to create codec debugfs directory\n"); -- cgit v1.2.3 From 3a45b8672d3f8542e430e7a5c7366ec9bdded054 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 5 Nov 2010 20:35:21 +0200 Subject: ASoC: Move pop time from DAPM context to sound card Based on discussion the dapm_pop_time in debugsfs should be per card rather than per device. Single pop time value for entire card is cleaner when the DAPM sequencing is extended to cross-device paths. debugfs/asoc/{card->name}/{codec dir}/dapm_pop_time -> debugfs/asoc/{card->name}/dapm_pop_time Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 57e5d7bfb130..f030521c48d1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -255,13 +255,6 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) printk(KERN_WARNING "ASoC: Failed to create codec register debugfs file\n"); - codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, - codec->debugfs_codec_root, - &codec->dapm.pop_time); - if (!codec->debugfs_pop_time) - printk(KERN_WARNING - "Failed to create pop time debugfs file\n"); - codec->dapm.debugfs_dapm = debugfs_create_dir("dapm", codec->debugfs_codec_root); if (!codec->dapm.debugfs_dapm) @@ -380,9 +373,18 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) { card->debugfs_card_root = debugfs_create_dir(card->name, debugfs_root); - if (!card->debugfs_card_root) + if (!card->debugfs_card_root) { dev_warn(card->dev, "ASoC: Failed to create codec debugfs directory\n"); + return; + } + + card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644, + card->debugfs_card_root, + &card->pop_time); + if (!card->debugfs_pop_time) + dev_warn(card->dev, + "Failed to create pop time debugfs file\n"); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) @@ -1426,6 +1428,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) /* probe the CODEC */ if (!codec->probed) { + codec->dapm.card = card; if (codec->driver->probe) { ret = codec->driver->probe(codec); if (ret < 0) { -- cgit v1.2.3 From b95fccbc025cb5788776ed8b80dba20b24529b15 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 9 Nov 2010 17:06:44 +0800 Subject: ASoC: Fix compile error if CONFIG_DEBUG_FS is not configured Add soc_init_card_debugfs and soc_cleanup_card_debugfs functions to fix below error. CC sound/soc/soc-core.o sound/soc/soc-core.c: In function 'soc_probe': sound/soc/soc-core.c:1689: error: implicit declaration of function 'soc_init_card_debugfs' sound/soc/soc-core.c: In function 'soc_remove': sound/soc/soc-core.c:1718: error: implicit declaration of function 'soc_cleanup_card_debugfs' make[2]: *** [sound/soc/soc-core.o] Error 1 make[1]: *** [sound/soc] Error 2 make: *** [sound] Error 2 Signed-off-by: Axel Lin Acked-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f030521c48d1..c18ce1dc51b8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -401,6 +401,14 @@ static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { } + +static inline void soc_init_card_debugfs(struct snd_soc_card *card) +{ +} + +static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card) +{ +} #endif #ifdef CONFIG_SND_SOC_AC97_BUS -- cgit v1.2.3 From a8b1d34f3ee1bc139ac5fbe3f84f6d16c90136bb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Nov 2010 18:05:58 -0400 Subject: ASoC: Add trace events for ASoC register read/write The trace subsystem provides a convenient way of instrumenting the kernel which can be left on all the time with extremely low impact on the system unlike prints to the kernel log which can be very spammy. Begin adding support for instrumenting ASoC via this interface by adding trace for the register access primitives. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c18ce1dc51b8..700a6d5b9721 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -39,6 +39,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #define NAME_SIZE 32 static DEFINE_MUTEX(pcm_mutex); @@ -1914,6 +1917,7 @@ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg) ret = codec->driver->read(codec, reg); dev_dbg(codec->dev, "read %x => %x\n", reg, ret); + trace_snd_soc_reg_read(codec, reg, ret); return ret; } @@ -1923,6 +1927,7 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { dev_dbg(codec->dev, "write %x = %x\n", reg, val); + trace_snd_soc_reg_write(codec, reg, val); return codec->driver->write(codec, reg, val); } EXPORT_SYMBOL_GPL(snd_soc_write); -- cgit v1.2.3 From 7a30a3db34cc7b2180a1a6c4a51d19d93c8a8b80 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Thu, 11 Nov 2010 10:04:57 +0000 Subject: ASoC: soc-cache: Add support for flat register caching This patch introduces the new caching API and migrates the old caching interface into the new one. The flat register caching technique does not use compression at all and it is equivalent to the old caching technique. One can still access codec->reg_cache directly but this is not advised as that will not be portable across different caching strategies. None of the existing drivers need to be changed to adapt to this caching technique. There should be no noticeable overhead associated with using the new caching API. Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 700a6d5b9721..3d70ce58d03c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3279,29 +3279,21 @@ int snd_soc_register_codec(struct device *dev, codec->dapm.bias_level = SND_SOC_BIAS_OFF; codec->dapm.dev = dev; codec->dapm.codec = codec; + codec->dev = dev; + codec->driver = codec_drv; + codec->num_dai = num_dai; + mutex_init(&codec->mutex); /* allocate CODEC register cache */ if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { - - if (codec_drv->reg_cache_default) - codec->reg_cache = kmemdup(codec_drv->reg_cache_default, - codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL); - else - codec->reg_cache = kzalloc(codec_drv->reg_cache_size * - codec_drv->reg_word_size, GFP_KERNEL); - - if (codec->reg_cache == NULL) { - kfree(codec->name); - kfree(codec); - return -ENOMEM; + ret = snd_soc_cache_init(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache compression type: %d\n", + ret); + goto error_cache; } } - codec->dev = dev; - codec->driver = codec_drv; - codec->num_dai = num_dai; - mutex_init(&codec->mutex); - for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); fixup_codec_formats(&dai_drv[i].capture); @@ -3311,7 +3303,7 @@ int snd_soc_register_codec(struct device *dev, if (num_dai) { ret = snd_soc_register_dais(dev, dai_drv, num_dai); if (ret < 0) - goto error; + goto error_dais; } mutex_lock(&client_mutex); @@ -3322,9 +3314,9 @@ int snd_soc_register_codec(struct device *dev, pr_debug("Registered codec '%s'\n", codec->name); return 0; -error: - if (codec->reg_cache) - kfree(codec->reg_cache); +error_dais: + snd_soc_cache_exit(codec); +error_cache: kfree(codec->name); kfree(codec); return ret; @@ -3358,8 +3350,7 @@ found: pr_debug("Unregistered codec '%s'\n", codec->name); - if (codec->reg_cache) - kfree(codec->reg_cache); + snd_soc_cache_exit(codec); kfree(codec->name); kfree(codec); } -- cgit v1.2.3 From ead9b9199c09653dd9b889933c7af75f020c7286 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sat, 13 Nov 2010 20:40:44 +0200 Subject: ASoC: Add optional name_prefix for codec kcontrol, widget and route names There is a need to prefix codec kcontrol, widget and internal route names in an ASoC machine that has multiple codecs with conflicting names. The name collision would occur when codec drivers try to registering kcontrols with the same name or when building audio paths. This patch introduces optional prefix_map into struct snd_soc_card. With it machine drivers can specify a unique name prefix to each codec that have conflicting names with anothers. Prefix to codec is matched with codec name. Following example illustrates a machine that has two same codec instances. Name collision from kcontrol registration is avoided by specifying a name prefix "foo" for the second codec. As the codec widget names are prefixed then second audio map for that codec shows a prefixed widget name. static const struct snd_soc_dapm_route map0[] = { {"Spk", NULL, "MONO"}, }; static const struct snd_soc_dapm_route map1[] = { {"Vibra", NULL, "foo MONO"}, }; static struct snd_soc_prefix_map codec_prefix[] = { { .dev_name = "codec.2", .name_prefix = "foo", }, }; static struct snd_soc_card card = { ... .prefix_map = codec_prefix, .num_prefixes = ARRAY_SIZE(codec_prefix), }; Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3d70ce58d03c..2540efd67ee7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1397,6 +1397,23 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) } } +static void soc_set_name_prefix(struct snd_soc_card *card, + struct snd_soc_codec *codec) +{ + int i; + + if (card->prefix_map == NULL) + return; + + for (i = 0; i < card->num_prefixes; i++) { + struct snd_soc_prefix_map *map = &card->prefix_map[i]; + if (map->dev_name && !strcmp(codec->name, map->dev_name)) { + codec->name_prefix = map->name_prefix; + break; + } + } +} + static void rtd_release(struct device *dev) {} static int soc_probe_dai_link(struct snd_soc_card *card, int num) @@ -1406,6 +1423,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; + const char *temp; int ret; dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num); @@ -1440,6 +1458,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) /* probe the CODEC */ if (!codec->probed) { codec->dapm.card = card; + soc_set_name_prefix(card, codec); if (codec->driver->probe) { ret = codec->driver->probe(codec); if (ret < 0) { @@ -1492,11 +1511,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) /* now that all clients have probed, initialise the DAI link */ if (dai_link->init) { + /* machine controls, routes and widgets are not prefixed */ + temp = rtd->codec->name_prefix; + rtd->codec->name_prefix = NULL; ret = dai_link->init(rtd); if (ret < 0) { printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name); return ret; } + rtd->codec->name_prefix = temp; } /* Make sure all DAPM widgets are instantiated */ @@ -2072,14 +2095,22 @@ int snd_soc_add_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls) { struct snd_card *card = codec->card->snd_card; + char prefixed_name[44], *name; int err, i; for (i = 0; i < num_controls; i++) { const struct snd_kcontrol_new *control = &controls[i]; - err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL)); + if (codec->name_prefix) { + snprintf(prefixed_name, sizeof(prefixed_name), "%s %s", + codec->name_prefix, control->name); + name = prefixed_name; + } else { + name = control->name; + } + err = snd_ctl_add(card, snd_soc_cnew(control, codec, name)); if (err < 0) { dev_err(codec->dev, "%s: Failed to add %s: %d\n", - codec->name, control->name, err); + codec->name, name, err); return err; } } -- cgit v1.2.3 From 505fb824e754efcc9702ce68d3911e7b86d3c690 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Sun, 21 Nov 2010 19:48:45 +0200 Subject: ASoC: Do not include soc-dapm.h There is no need to include soc-dapm.h since soc.h includes it. Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2540efd67ee7..c8d8dde7f4dd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #define CREATE_TRACE_POINTS -- cgit v1.2.3 From 2eea392d0a28a0a07d36a9da544eb40f81bf4cb6 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Nov 2010 17:47:38 +0200 Subject: ASoC: Add support for optional auxiliary dailess codecs This makes possible to register auxiliary dailess codecs in a machine driver. Term dailess is used here for amplifiers and codecs without DAI or DAI being unused. Dailess auxiliary codecs are kept in struct snd_soc_aux_dev and those codecs are probed after initializing the DAI links. There are no major differences between DAI link codecs and dailess codecs in ASoC core point of view. DAPM handles them equally and sysfs and debugfs directories for dailess codecs are similar except the pmdown_time node is not created. Only suspend and resume functions are modified to traverse all probed codecs instead of DAI link codecs. Example below shows a dailess codec registration. struct snd_soc_aux_dev foo_aux_dev[] = { { .name = "Amp", .codec_name = "codec.2", .init = foo_init2, }, }; static struct snd_soc_card card = { ... .aux_dev = foo_aux_dev, .num_aux_devs = ARRAY_SIZE(foo_aux_dev), }; Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 6 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c8d8dde7f4dd..a7670d5ac13d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -986,6 +986,7 @@ static int soc_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct snd_soc_card *card = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; int i; /* If the initialization of this soc device failed, there is no codec @@ -1064,8 +1065,7 @@ static int soc_suspend(struct device *dev) } /* suspend all CODECs */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_codec *codec = card->rtd[i].codec; + list_for_each_entry(codec, &card->codec_dev_list, card_list) { /* If there are paths active then the CODEC will be held with * bias _ON and should not be suspended. */ if (!codec->suspended && codec->driver->suspend) { @@ -1106,6 +1106,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_card *card = container_of(work, struct snd_soc_card, deferred_resume_work); struct platform_device *pdev = to_platform_device(card->dev); + struct snd_soc_codec *codec; int i; /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, @@ -1131,8 +1132,7 @@ static void soc_resume_deferred(struct work_struct *work) cpu_dai->driver->resume(cpu_dai); } - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_codec *codec = card->rtd[i].codec; + list_for_each_entry(codec, &card->codec_dev_list, card_list) { /* If the CODEC was idle over suspend then it will have been * left with bias OFF or STANDBY and suspended so we must now * resume. Otherwise the suspend was suppressed. @@ -1603,6 +1603,130 @@ static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec) } #endif +static int soc_probe_aux_dev(struct snd_soc_card *card, int num) +{ + struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; + struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; + struct snd_soc_codec *codec; + const char *temp; + int ret = 0; + + /* find CODEC from registered CODECs*/ + list_for_each_entry(codec, &codec_list, list) { + if (!strcmp(codec->name, aux_dev->codec_name)) { + if (codec->probed) { + dev_err(codec->dev, + "asoc: codec already probed"); + ret = -EBUSY; + goto out; + } + break; + } + } + + if (!try_module_get(codec->dev->driver->owner)) + return -ENODEV; + + codec->card = card; + codec->dapm.card = card; + + soc_set_name_prefix(card, codec); + if (codec->driver->probe) { + ret = codec->driver->probe(codec); + if (ret < 0) { + dev_err(codec->dev, "asoc: failed to probe CODEC"); + return ret; + } + } + + soc_init_codec_debugfs(codec); + + /* mark codec as probed and add to card codec list */ + codec->probed = 1; + list_add(&codec->card_list, &card->codec_dev_list); + list_add(&codec->dapm.list, &card->dapm_list); + + /* now that all clients have probed, initialise the DAI link */ + if (aux_dev->init) { + /* machine controls, routes and widgets are not prefixed */ + temp = codec->name_prefix; + codec->name_prefix = NULL; + ret = aux_dev->init(&codec->dapm); + if (ret < 0) { + dev_err(codec->dev, + "asoc: failed to init %s\n", aux_dev->name); + return ret; + } + codec->name_prefix = temp; + } + + /* Make sure all DAPM widgets are instantiated */ + snd_soc_dapm_new_widgets(&codec->dapm); + snd_soc_dapm_sync(&codec->dapm); + + /* register the rtd device */ + rtd->codec = codec; + rtd->card = card; + rtd->dev.parent = card->dev; + rtd->dev.release = rtd_release; + rtd->dev.init_name = aux_dev->name; + ret = device_register(&rtd->dev); + if (ret < 0) { + dev_err(codec->dev, + "asoc: failed to register aux runtime device %d\n", + ret); + return ret; + } + rtd->dev_registered = 1; + + /* add DAPM sysfs entries for this codec */ + ret = snd_soc_dapm_sys_add(&rtd->dev); + if (ret < 0) + dev_err(codec->dev, + "asoc: failed to add codec dapm sysfs entries\n"); + + /* add codec sysfs entries */ + ret = device_create_file(&rtd->dev, &dev_attr_codec_reg); + if (ret < 0) + dev_err(codec->dev, "asoc: failed to add codec sysfs files\n"); + +out: + return ret; +} + +static void soc_remove_aux_dev(struct snd_soc_card *card, int num) +{ + struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; + struct snd_soc_codec *codec = rtd->codec; + int err; + + /* unregister the rtd device */ + if (rtd->dev_registered) { + device_unregister(&rtd->dev); + rtd->dev_registered = 0; + } + + /* remove the CODEC */ + if (codec && codec->probed) { + if (codec->driver->remove) { + err = codec->driver->remove(codec); + if (err < 0) + dev_err(codec->dev, + "asoc: failed to remove %s\n", + codec->name); + } + + /* Make sure all DAPM widgets are freed */ + snd_soc_dapm_free(&codec->dapm); + + soc_cleanup_codec_debugfs(codec); + device_remove_file(&rtd->dev, &dev_attr_codec_reg); + codec->probed = 0; + list_del(&codec->card_list); + module_put(codec->dev->driver->owner); + } +} + static void snd_soc_instantiate_card(struct snd_soc_card *card) { struct platform_device *pdev = to_platform_device(card->dev); @@ -1657,6 +1781,15 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) } } + for (i = 0; i < card->num_aux_devs; i++) { + ret = soc_probe_aux_dev(card, i); + if (ret < 0) { + pr_err("asoc: failed to add auxiliary devices %s: %d\n", + card->name, ret); + goto probe_aux_dev_err; + } + } + snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), "%s", card->name); snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), @@ -1683,6 +1816,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) mutex_unlock(&card->mutex); return; +probe_aux_dev_err: + for (i = 0; i < card->num_aux_devs; i++) + soc_remove_aux_dev(card, i); + probe_dai_err: for (i = 0; i < card->num_links; i++) soc_remove_dai_link(card, i); @@ -1744,6 +1881,10 @@ static int soc_remove(struct platform_device *pdev) run_delayed_work(&rtd->delayed_work); } + /* remove auxiliary devices */ + for (i = 0; i < card->num_aux_devs; i++) + soc_remove_aux_dev(card, i); + /* remove and free each DAI */ for (i = 0; i < card->num_rtd; i++) soc_remove_dai_link(card, i); @@ -2946,10 +3087,12 @@ static int snd_soc_register_card(struct snd_soc_card *card) if (!card->name || !card->dev) return -EINVAL; - card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links, - GFP_KERNEL); + card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * + (card->num_links + card->num_aux_devs), + GFP_KERNEL); if (card->rtd == NULL) return -ENOMEM; + card->rtd_aux = &card->rtd[card->num_links]; for (i = 0; i < card->num_links; i++) card->rtd[i].dai_link = &card->dai_link[i]; -- cgit v1.2.3 From 06c6f4d34a23f7c9c783f1a875bb492b15fa23ac Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 1 Dec 2010 09:10:47 +0200 Subject: ASoC: Fix build failure in soc-core.c Commit 2eea392 "ASoC: Add support for optional auxiliary dailess codecs" causes a build failure in soc-core.c: soc_probe_aux_dev since code tries to access non-existing struct snd_soc_dapm_context and struct snd_soc_card members. Root cause for this was a double accident. Author sent the RFC patch from top of another patch set and the RFC got committed. Fix the build failure by removing the code line that depends on that another patch set. Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a7670d5ac13d..eb950f73076a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1644,7 +1644,6 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) /* mark codec as probed and add to card codec list */ codec->probed = 1; list_add(&codec->card_list, &card->codec_dev_list); - list_add(&codec->dapm.list, &card->dapm_list); /* now that all clients have probed, initialise the DAI link */ if (aux_dev->init) { -- cgit v1.2.3 From a00f90f9306c06bee8e909628f39052bb3b0cc9e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Dec 2010 16:24:24 +0000 Subject: ASoC: Apostrophe patrol in soc-core.c Silly little grammar nit but it bugs the hell out of me. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eb950f73076a..20dcc978588f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -525,7 +525,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - /* Check that the codec and cpu DAI's are compatible */ + /* Check that the codec and cpu DAIs are compatible */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { runtime->hw.rate_min = max(codec_dai_drv->playback.rate_min, @@ -874,7 +874,7 @@ codec_err: } /* - * Free's resources allocated by hw_params, can be called multiple times + * Frees resources allocated by hw_params, can be called multiple times */ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) { @@ -898,7 +898,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) if (platform->driver->ops->hw_free) platform->driver->ops->hw_free(substream); - /* now free hw params for the DAI's */ + /* now free hw params for the DAIs */ if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); @@ -1005,7 +1005,7 @@ static int soc_suspend(struct device *dev) /* we're going to block userspace touching us until resume completes */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); - /* mute any active DAC's */ + /* mute any active DACs */ for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *dai = card->rtd[i].codec_dai; struct snd_soc_dai_driver *drv = dai->driver; -- cgit v1.2.3 From c3acec2671cc448bc549b06b561ae2454238e9a0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Dec 2010 16:15:29 +0000 Subject: ASoC: Move active copy of CODEC read and write into runtime structure We shouldn't be assigning to the driver structure (which really ought to be const, further patch to follow) though there's unlikely to be any actual problem except in the unlikely case that two devices with the same driver but different bus types appear in the same system. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 20dcc978588f..5720dbcefbc4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2077,7 +2077,7 @@ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg) { unsigned int ret; - ret = codec->driver->read(codec, reg); + ret = codec->read(codec, reg); dev_dbg(codec->dev, "read %x => %x\n", reg, ret); trace_snd_soc_reg_read(codec, reg, ret); @@ -2090,7 +2090,7 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec, { dev_dbg(codec->dev, "write %x = %x\n", reg, val); trace_snd_soc_reg_write(codec, reg, val); - return codec->driver->write(codec, reg, val); + return codec->write(codec, reg, val); } EXPORT_SYMBOL_GPL(snd_soc_write); @@ -3448,6 +3448,8 @@ int snd_soc_register_codec(struct device *dev, INIT_LIST_HEAD(&codec->dapm.widgets); INIT_LIST_HEAD(&codec->dapm.paths); + codec->write = codec_drv->write; + codec->read = codec_drv->read; codec->dapm.bias_level = SND_SOC_BIAS_OFF; codec->dapm.dev = dev; codec->dapm.codec = codec; -- cgit v1.2.3 From 676ad98a06a629e6273819a54b70f3987044b608 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 3 Dec 2010 09:18:22 +0200 Subject: ASoC: Don't oops in soc_probe_aux_dev in case of missing codec Blind copy of codec finding algorithm from soc_bind_dai_link does not work in soc_probe_aux_dev if matching codec name is not found. In that case the code falls through and tries to start the probing procedure with invalid codec pointer. Fix this and add an error print showing the codec name that cannot be found. Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5720dbcefbc4..2b1fcae4131e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1609,7 +1609,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_codec *codec; const char *temp; - int ret = 0; + int ret = -ENODEV; /* find CODEC from registered CODECs*/ list_for_each_entry(codec, &codec_list, list) { @@ -1620,10 +1620,14 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) ret = -EBUSY; goto out; } - break; + goto found; } } + /* codec not found */ + dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name); + goto out; +found: if (!try_module_get(codec->dev->driver->owner)) return -ENODEV; -- cgit v1.2.3 From 23bbce34f47762ce944ea9b8b3b3e05e220c6a2e Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Thu, 2 Dec 2010 14:53:01 +0000 Subject: ASoC: Add compress_type as a member to snd_soc_codec We need to keep a copy of the compress_type supplied by the codec driver so that we can override it if necessary with whatever the machine driver has provided us with. The reason for not modifying the codec->driver struct directly is that ideally we'd like to keep it const. Adjust the code in soc-cache and soc-core to make use of the compress_type member in the snd_soc_codec struct. Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2b1fcae4131e..1fd1d1a62af1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3450,6 +3450,11 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; } + if (codec_drv->compress_type) + codec->compress_type = codec_drv->compress_type; + else + codec->compress_type = SND_SOC_FLAT_COMPRESSION; + INIT_LIST_HEAD(&codec->dapm.widgets); INIT_LIST_HEAD(&codec->dapm.paths); codec->write = codec_drv->write; -- cgit v1.2.3 From ff819b8357df0ca9903ff7c9ad518b949c410123 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Thu, 2 Dec 2010 14:53:03 +0000 Subject: ASoC: soc-core: Generalize snd_soc_prefix_map and rename to snd_soc_codec_conf The snd_soc_codec_conf struct now holds codec specific configuration information. A new configuration option has been added to allow machine drivers to override the compression type set by the codec driver. In the absence of providing an snd_soc_codec_conf struct or when providing one but not setting the compress_type member to anything, the one supplied by the codec driver will be used instead. In all other cases the one set in the snd_soc_codec_conf struct takes effect. Signed-off-by: Dimitris Papastamos Acked-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1fd1d1a62af1..4649db6163b8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1401,11 +1401,11 @@ static void soc_set_name_prefix(struct snd_soc_card *card, { int i; - if (card->prefix_map == NULL) + if (card->codec_conf == NULL) return; - for (i = 0; i < card->num_prefixes; i++) { - struct snd_soc_prefix_map *map = &card->prefix_map[i]; + for (i = 0; i < card->num_configs; i++) { + struct snd_soc_codec_conf *map = &card->codec_conf[i]; if (map->dev_name && !strcmp(codec->name, map->dev_name)) { codec->name_prefix = map->name_prefix; break; -- cgit v1.2.3 From 3335ddca9367675f4ee0bd50cc70402c4919a10d Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Thu, 2 Dec 2010 16:11:05 +0000 Subject: ASoC: soc-cache: Use reg_def_copy instead of reg_cache_default Make sure to use codec->reg_def_copy instead of codec_drv->reg_cache_default wherever necessary. This change is necessary because in the next patch we move the cache initialization code outside snd_soc_register_codec() and by that time any data marked as __devinitconst such as the original reg_cache_default array might have already been freed by the kernel. Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4649db6163b8..a95d111a6531 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3434,6 +3434,7 @@ int snd_soc_register_codec(struct device *dev, struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai) { + size_t reg_size; struct snd_soc_codec *codec; int ret, i; @@ -3469,6 +3470,19 @@ int snd_soc_register_codec(struct device *dev, /* allocate CODEC register cache */ if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { + reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; + /* it is necessary to make a copy of the default register cache + * because in the case of using a compression type that requires + * the default register cache to be marked as __devinitconst the + * kernel might have freed the array by the time we initialize + * the cache. + */ + codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default, + reg_size, GFP_KERNEL); + if (!codec->reg_def_copy) { + ret = -ENOMEM; + goto error_cache; + } ret = snd_soc_cache_init(codec); if (ret < 0) { dev_err(codec->dev, "Failed to set cache compression type: %d\n", @@ -3500,6 +3514,8 @@ int snd_soc_register_codec(struct device *dev, error_dais: snd_soc_cache_exit(codec); error_cache: + kfree(codec->reg_def_copy); + codec->reg_def_copy = NULL; kfree(codec->name); kfree(codec); return ret; @@ -3534,6 +3550,7 @@ found: pr_debug("Unregistered codec '%s'\n", codec->name); snd_soc_cache_exit(codec); + kfree(codec->reg_def_copy); kfree(codec->name); kfree(codec); } -- cgit v1.2.3 From fdf0f54dab8e401fd9bdd441c3fc4fa5c8837646 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Thu, 2 Dec 2010 16:11:06 +0000 Subject: ASoC: soc-core: Allow machine drivers to override compress_type This patch allows machine drivers to override the compression type provided by the codec driver. Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 74 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a95d111a6531..e9aa9ce59c06 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1730,9 +1730,36 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) } } +static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, + enum snd_soc_compress_type compress_type) +{ + int ret; + + if (codec->cache_init) + return 0; + + /* override the compress_type if necessary */ + if (compress_type && codec->compress_type != compress_type) + codec->compress_type = compress_type; + dev_dbg(codec->dev, "Cache compress_type for %s is %d\n", + codec->name, codec->compress_type); + ret = snd_soc_cache_init(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache compression type: %d\n", + ret); + return ret; + } + codec->cache_init = 1; + return 0; +} + + static void snd_soc_instantiate_card(struct snd_soc_card *card) { struct platform_device *pdev = to_platform_device(card->dev); + struct snd_soc_codec *codec; + struct snd_soc_codec_conf *codec_conf; + enum snd_soc_compress_type compress_type; int ret, i; mutex_lock(&card->mutex); @@ -1752,6 +1779,39 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) return; } + /* initialize the register cache for each available codec */ + list_for_each_entry(codec, &codec_list, list) { + if (codec->cache_init) + continue; + /* check to see if we need to override the compress_type */ + for (i = 0; i < card->num_configs; ++i) { + codec_conf = &card->codec_conf[i]; + if (!strcmp(codec->name, codec_conf->dev_name)) { + compress_type = codec_conf->compress_type; + if (compress_type && compress_type + != codec->compress_type) + break; + } + } + if (i == card->num_configs) { + /* no need to override the compress_type so + * go ahead and do the standard thing */ + ret = snd_soc_init_codec_cache(codec, 0); + if (ret < 0) { + mutex_unlock(&card->mutex); + return; + } + continue; + } + /* override the compress_type with the one supplied in + * the machine driver */ + ret = snd_soc_init_codec_cache(codec, compress_type); + if (ret < 0) { + mutex_unlock(&card->mutex); + return; + } + } + /* card bind complete so register a sound card */ ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, card->owner, 0, &card->snd_card); @@ -3481,13 +3541,7 @@ int snd_soc_register_codec(struct device *dev, reg_size, GFP_KERNEL); if (!codec->reg_def_copy) { ret = -ENOMEM; - goto error_cache; - } - ret = snd_soc_cache_init(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache compression type: %d\n", - ret); - goto error_cache; + goto fail; } } @@ -3500,7 +3554,7 @@ int snd_soc_register_codec(struct device *dev, if (num_dai) { ret = snd_soc_register_dais(dev, dai_drv, num_dai); if (ret < 0) - goto error_dais; + goto fail; } mutex_lock(&client_mutex); @@ -3511,9 +3565,7 @@ int snd_soc_register_codec(struct device *dev, pr_debug("Registered codec '%s'\n", codec->name); return 0; -error_dais: - snd_soc_cache_exit(codec); -error_cache: +fail: kfree(codec->reg_def_copy); codec->reg_def_copy = NULL; kfree(codec->name); -- cgit v1.2.3 From 001ae4c0350a35e8358514326e5c3d165357979a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Dec 2010 16:21:08 +0000 Subject: ASoC: Constify struct snd_soc_codec_driver Allow the CODEC driver structure to be marked const by making all the APIs that use it do so. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e9aa9ce59c06..78a01014079a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3491,8 +3491,9 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) * @codec: codec to register */ int snd_soc_register_codec(struct device *dev, - struct snd_soc_codec_driver *codec_drv, - struct snd_soc_dai_driver *dai_drv, int num_dai) + const struct snd_soc_codec_driver *codec_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) { size_t reg_size; struct snd_soc_codec *codec; -- cgit v1.2.3 From 3028eb8c51d968b9e7b44a9786a4e521e37afb13 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 5 Dec 2010 12:22:46 +0000 Subject: ASoC: Add trace events for jack detection As jack detection can trigger DAPM and the latency in debouncing can create confusing windows in operation provide some trace events which will hopefully help in diagnostics. The soc-jack core traces all reports that it gets and the resulting notifications to upper layers. An event for jack IRQs is also provided for instrumentation of debounce, and used in the GPIO jack code. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 78a01014079a..822bd3bcf148 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 0d735eaa2c1d80c997fd775b679e36b80b8e85d1 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Mon, 6 Dec 2010 09:51:57 +0000 Subject: ASoC: soc-cache: Add optional cache name member to snd_soc_cache_ops Added an optional name member to snd_soc_cache_ops to enable more sensible diagnostic messages during cache init, exit and sync. Remove redundant newline in source code. Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 822bd3bcf148..a90e067fb0ab 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1742,8 +1742,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, /* override the compress_type if necessary */ if (compress_type && codec->compress_type != compress_type) codec->compress_type = compress_type; - dev_dbg(codec->dev, "Cache compress_type for %s is %d\n", - codec->name, codec->compress_type); ret = snd_soc_cache_init(codec); if (ret < 0) { dev_err(codec->dev, "Failed to set cache compression type: %d\n", @@ -1754,7 +1752,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, return 0; } - static void snd_soc_instantiate_card(struct snd_soc_card *card) { struct platform_device *pdev = to_platform_device(card->dev); -- cgit v1.2.3 From 589c3563f6476950f26b5bcc9beb1b39a7bcc644 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 6 Dec 2010 16:27:07 +0200 Subject: ASoC: Merge common code in DAI link and auxiliary codec probing/removal Commit 2eea392 "ASoC: Add support for optional auxiliary dailess codecs" added much of code that can be shared with DAI link codec probing/removal. Merge now this common code into new soc_probe_codec, soc_remove_codec and soc_post_component_init functions. Error prints in these functions are converted to use dev_err and to print the error code. Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 284 ++++++++++++++++++++++++--------------------------- 1 file changed, 132 insertions(+), 152 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 17dcd56a2520..b3605a1c8c46 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1328,6 +1328,27 @@ out: return 1; } +static void soc_remove_codec(struct snd_soc_codec *codec) +{ + int err; + + if (codec->driver->remove) { + err = codec->driver->remove(codec); + if (err < 0) + dev_err(codec->dev, + "asoc: failed to remove %s: %d\n", + codec->name, err); + } + + /* Make sure all DAPM widgets are freed */ + snd_soc_dapm_free(&codec->dapm); + + soc_cleanup_codec_debugfs(codec); + codec->probed = 0; + list_del(&codec->card_list); + module_put(codec->dev->driver->owner); +} + static void soc_remove_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; @@ -1339,6 +1360,7 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) /* unregister the rtd device */ if (rtd->dev_registered) { device_remove_file(&rtd->dev, &dev_attr_pmdown_time); + device_remove_file(&rtd->dev, &dev_attr_codec_reg); device_unregister(&rtd->dev); rtd->dev_registered = 0; } @@ -1367,22 +1389,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) } /* remove the CODEC */ - if (codec && codec->probed) { - if (codec->driver->remove) { - err = codec->driver->remove(codec); - if (err < 0) - printk(KERN_ERR "asoc: failed to remove %s\n", codec->name); - } - - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&codec->dapm); - - soc_cleanup_codec_debugfs(codec); - device_remove_file(&rtd->dev, &dev_attr_codec_reg); - codec->probed = 0; - list_del(&codec->card_list); - module_put(codec->dev->driver->owner); - } + if (codec && codec->probed) + soc_remove_codec(codec); /* remove the cpu_dai */ if (cpu_dai && cpu_dai->probed) { @@ -1414,8 +1422,105 @@ static void soc_set_name_prefix(struct snd_soc_card *card, } } +static int soc_probe_codec(struct snd_soc_card *card, + struct snd_soc_codec *codec) +{ + int ret = 0; + + codec->card = card; + codec->dapm.card = card; + soc_set_name_prefix(card, codec); + + if (codec->driver->probe) { + ret = codec->driver->probe(codec); + if (ret < 0) { + dev_err(codec->dev, + "asoc: failed to probe CODEC %s: %d\n", + codec->name, ret); + return ret; + } + } + + soc_init_codec_debugfs(codec); + + /* mark codec as probed and add to card codec list */ + codec->probed = 1; + list_add(&codec->card_list, &card->codec_dev_list); + + return ret; +} + static void rtd_release(struct device *dev) {} +static int soc_post_component_init(struct snd_soc_card *card, + struct snd_soc_codec *codec, + int num, int dailess) +{ + struct snd_soc_dai_link *dai_link = NULL; + struct snd_soc_aux_dev *aux_dev = NULL; + struct snd_soc_pcm_runtime *rtd; + const char *temp, *name; + int ret = 0; + + if (!dailess) { + dai_link = &card->dai_link[num]; + rtd = &card->rtd[num]; + name = dai_link->name; + } else { + aux_dev = &card->aux_dev[num]; + rtd = &card->rtd_aux[num]; + name = aux_dev->name; + } + + /* machine controls, routes and widgets are not prefixed */ + temp = codec->name_prefix; + codec->name_prefix = NULL; + + /* do machine specific initialization */ + if (!dailess && dai_link->init) + ret = dai_link->init(rtd); + else if (dailess && aux_dev->init) + ret = aux_dev->init(&codec->dapm); + if (ret < 0) { + dev_err(card->dev, "asoc: failed to init %s: %d\n", name, ret); + return ret; + } + codec->name_prefix = temp; + + /* Make sure all DAPM widgets are instantiated */ + snd_soc_dapm_new_widgets(&codec->dapm); + snd_soc_dapm_sync(&codec->dapm); + + /* register the rtd device */ + rtd->codec = codec; + rtd->card = card; + rtd->dev.parent = card->dev; + rtd->dev.release = rtd_release; + rtd->dev.init_name = name; + ret = device_register(&rtd->dev); + if (ret < 0) { + dev_err(card->dev, + "asoc: failed to register runtime device: %d\n", ret); + return ret; + } + rtd->dev_registered = 1; + + /* add DAPM sysfs entries for this codec */ + ret = snd_soc_dapm_sys_add(&rtd->dev); + if (ret < 0) + dev_err(codec->dev, + "asoc: failed to add codec dapm sysfs entries: %d\n", + ret); + + /* add codec sysfs entries */ + ret = device_create_file(&rtd->dev, &dev_attr_codec_reg); + if (ret < 0) + dev_err(codec->dev, + "asoc: failed to add codec sysfs files: %d\n", ret); + + return 0; +} + static int soc_probe_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; @@ -1423,17 +1528,13 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) struct snd_soc_codec *codec = rtd->codec; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; - const char *temp; int ret; dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num); /* config components */ codec_dai->codec = codec; - codec->card = card; cpu_dai->platform = platform; - rtd->card = card; - rtd->dev.parent = card->dev; codec_dai->card = card; cpu_dai->card = card; @@ -1457,22 +1558,9 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) /* probe the CODEC */ if (!codec->probed) { - codec->dapm.card = card; - soc_set_name_prefix(card, codec); - if (codec->driver->probe) { - ret = codec->driver->probe(codec); - if (ret < 0) { - printk(KERN_ERR "asoc: failed to probe CODEC %s\n", - codec->name); - return ret; - } - } - - soc_init_codec_debugfs(codec); - - /* mark codec as probed and add to card codec list */ - codec->probed = 1; - list_add(&codec->card_list, &card->codec_dev_list); + ret = soc_probe_codec(card, codec); + if (ret < 0) + return ret; } /* probe the platform */ @@ -1509,47 +1597,14 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); - /* now that all clients have probed, initialise the DAI link */ - if (dai_link->init) { - /* machine controls, routes and widgets are not prefixed */ - temp = rtd->codec->name_prefix; - rtd->codec->name_prefix = NULL; - ret = dai_link->init(rtd); - if (ret < 0) { - printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name); - return ret; - } - rtd->codec->name_prefix = temp; - } - - /* Make sure all DAPM widgets are instantiated */ - snd_soc_dapm_new_widgets(&codec->dapm); - snd_soc_dapm_sync(&codec->dapm); - - /* register the rtd device */ - rtd->dev.release = rtd_release; - rtd->dev.init_name = dai_link->name; - ret = device_register(&rtd->dev); - if (ret < 0) { - printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret); + ret = soc_post_component_init(card, codec, num, 0); + if (ret) return ret; - } - rtd->dev_registered = 1; ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time); if (ret < 0) printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n"); - /* add DAPM sysfs entries for this codec */ - ret = snd_soc_dapm_sys_add(&rtd->dev); - if (ret < 0) - printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n"); - - /* add codec sysfs entries */ - ret = device_create_file(&rtd->dev, &dev_attr_codec_reg); - if (ret < 0) - printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); - /* create the pcm */ ret = soc_new_pcm(rtd, num); if (ret < 0) { @@ -1607,9 +1662,7 @@ static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec) static int soc_probe_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_codec *codec; - const char *temp; int ret = -ENODEV; /* find CODEC from registered CODECs*/ @@ -1632,67 +1685,11 @@ found: if (!try_module_get(codec->dev->driver->owner)) return -ENODEV; - codec->card = card; - codec->dapm.card = card; - - soc_set_name_prefix(card, codec); - if (codec->driver->probe) { - ret = codec->driver->probe(codec); - if (ret < 0) { - dev_err(codec->dev, "asoc: failed to probe CODEC"); - return ret; - } - } - - soc_init_codec_debugfs(codec); - - /* mark codec as probed and add to card codec list */ - codec->probed = 1; - list_add(&codec->card_list, &card->codec_dev_list); - - /* now that all clients have probed, initialise the DAI link */ - if (aux_dev->init) { - /* machine controls, routes and widgets are not prefixed */ - temp = codec->name_prefix; - codec->name_prefix = NULL; - ret = aux_dev->init(&codec->dapm); - if (ret < 0) { - dev_err(codec->dev, - "asoc: failed to init %s\n", aux_dev->name); - return ret; - } - codec->name_prefix = temp; - } - - /* Make sure all DAPM widgets are instantiated */ - snd_soc_dapm_new_widgets(&codec->dapm); - snd_soc_dapm_sync(&codec->dapm); - - /* register the rtd device */ - rtd->codec = codec; - rtd->card = card; - rtd->dev.parent = card->dev; - rtd->dev.release = rtd_release; - rtd->dev.init_name = aux_dev->name; - ret = device_register(&rtd->dev); - if (ret < 0) { - dev_err(codec->dev, - "asoc: failed to register aux runtime device %d\n", - ret); - return ret; - } - rtd->dev_registered = 1; - - /* add DAPM sysfs entries for this codec */ - ret = snd_soc_dapm_sys_add(&rtd->dev); + ret = soc_probe_codec(card, codec); if (ret < 0) - dev_err(codec->dev, - "asoc: failed to add codec dapm sysfs entries\n"); + return ret; - /* add codec sysfs entries */ - ret = device_create_file(&rtd->dev, &dev_attr_codec_reg); - if (ret < 0) - dev_err(codec->dev, "asoc: failed to add codec sysfs files\n"); + ret = soc_post_component_init(card, codec, num, 1); out: return ret; @@ -1702,33 +1699,16 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_codec *codec = rtd->codec; - int err; /* unregister the rtd device */ if (rtd->dev_registered) { + device_remove_file(&rtd->dev, &dev_attr_codec_reg); device_unregister(&rtd->dev); rtd->dev_registered = 0; } - /* remove the CODEC */ - if (codec && codec->probed) { - if (codec->driver->remove) { - err = codec->driver->remove(codec); - if (err < 0) - dev_err(codec->dev, - "asoc: failed to remove %s\n", - codec->name); - } - - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&codec->dapm); - - soc_cleanup_codec_debugfs(codec); - device_remove_file(&rtd->dev, &dev_attr_codec_reg); - codec->probed = 0; - list_del(&codec->card_list); - module_put(codec->dev->driver->owner); - } + if (codec && codec->probed) + soc_remove_codec(codec); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, -- cgit v1.2.3 From 58818a77cd415e2f76607749de5a1ff24e58cefe Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Mon, 6 Dec 2010 15:42:17 +0000 Subject: ASoC: soc-core: Replace use of strncpy() with strlcpy() By using strncpy() if the source string does not have a null byte in the first n bytes, then the destination string is not null-terminated. This can be fixed in a two-step process by manually null-terminating the array after the use of strncpy() or by using strlcpy(). Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b3605a1c8c46..b2c327b14b00 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3183,7 +3183,7 @@ static inline char *fmt_single_name(struct device *dev, int *id) if (dev_name(dev) == NULL) return NULL; - strncpy(name, dev_name(dev), NAME_SIZE); + strlcpy(name, dev_name(dev), NAME_SIZE); /* are we a "%s.%d" name (platform and SPI components) */ found = strstr(name, dev->driver->name); @@ -3206,7 +3206,7 @@ static inline char *fmt_single_name(struct device *dev, int *id) /* sanitize component name for DAI link creation */ snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name); - strncpy(name, tmp, NAME_SIZE); + strlcpy(name, tmp, NAME_SIZE); } else *id = 0; } -- cgit v1.2.3 From 0b9a214a606f8c7c7af3e66e7fe0caf3233cfe16 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Mon, 6 Dec 2010 15:49:20 +0000 Subject: ASoC: soc-core: Remove useless inline function construct There is no need to mark this function as inline. Inline functions usually are small and concise functions that benefit from not needing to set up a stack frame and undergo a call/ret sequence upon each invocation. Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b2c327b14b00..392d33625327 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3175,7 +3175,7 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) * Simplify DAI link configuration by removing ".-1" from device names * and sanitizing names. */ -static inline char *fmt_single_name(struct device *dev, int *id) +static char *fmt_single_name(struct device *dev, int *id) { char *found, name[NAME_SIZE]; int id1, id2; -- cgit v1.2.3 From 6b3ed78535c5af8c1d25ed7eaaea7557698843a1 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Dec 2010 16:12:29 +0800 Subject: ASoC: Fix snd_soc_instantiate_card error path Properly free the resources in the case of snd_card_register failure and soc_register_ac97_dai_link failure. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 392d33625327..b4c8c3800503 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1839,18 +1839,20 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) ret = snd_card_register(card->snd_card); if (ret < 0) { printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name); - goto probe_dai_err; + goto probe_aux_dev_err; } #ifdef CONFIG_SND_SOC_AC97_BUS /* register any AC97 codecs */ for (i = 0; i < card->num_rtd; i++) { - ret = soc_register_ac97_dai_link(&card->rtd[i]); - if (ret < 0) { - printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); - goto probe_dai_err; - } + ret = soc_register_ac97_dai_link(&card->rtd[i]); + if (ret < 0) { + printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); + while (--i >= 0) + soc_unregister_ac97_dai_link(&card->rtd[i]); + goto probe_aux_dev_err; } + } #endif card->instantiated = 1; -- cgit v1.2.3 From e4f078d8c0790e94e09af975ca0b870e2f050e17 Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Tue, 7 Dec 2010 16:30:38 +0000 Subject: ASoC: soc-core: Fix null pointer dereference In case the codec driver did not provide a read/write function, codec->driver->read|write will be NULL. Ensure that we use the one specified in codec->read|write to avoid oopsing when we access the debugfs entries. This is achieved by using snd_soc_read() and snd_soc_write(). Signed-off-by: Dimitris Papastamos Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b4c8c3800503..a14a0507bbd0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -117,7 +117,7 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) * the register being volatile and the device being * powered off. */ - ret = codec->driver->read(codec, i); + ret = snd_soc_read(codec, i); if (ret >= 0) count += snprintf(buf + count, PAGE_SIZE - count, @@ -228,7 +228,7 @@ static ssize_t codec_reg_write_file(struct file *file, start++; if (strict_strtoul(start, 16, &value)) return -EINVAL; - codec->driver->write(codec, reg, value); + snd_soc_write(codec, reg, value); return buf_size; } -- cgit v1.2.3 From 5b84ba26a9672e615897234fa5efd3eea2d6b295 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 11 Dec 2010 17:51:26 +0100 Subject: sound: don't use flush_scheduled_work() flush_scheduled_work() is deprecated and scheduled to be removed. * cancel[_delayed]_work() + flush_scheduled_work() -> cancel[_delayed]_work_sync(). * wm8350, wm8753 and soc-core use custom code to cancel a delayed work, execute it immediately if it was pending and wait for its completion. This is equivalent to flush_delayed_work_sync(). Use it instead. Signed-off-by: Tejun Heo Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/soc-core.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 441285ade024..b54ea9a0a1db 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -67,25 +67,6 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); -/* - * This function forces any delayed work to be queued and run. - */ -static int run_delayed_work(struct delayed_work *dwork) -{ - int ret; - - /* cancel any work waiting to be queued. */ - ret = cancel_delayed_work(dwork); - - /* if there was any work waiting then we run it now and - * wait for it's completion */ - if (ret) { - schedule_delayed_work(dwork, 0); - flush_scheduled_work(); - } - return ret; -} - /* codec register dump */ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) { @@ -1016,7 +997,7 @@ static int soc_suspend(struct device *dev) /* close any waiting streams and save state */ for (i = 0; i < card->num_rtd; i++) { - run_delayed_work(&card->rtd[i].delayed_work); + flush_delayed_work_sync(&card->rtd[i].delayed_work); card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level; } @@ -1687,7 +1668,7 @@ static int soc_remove(struct platform_device *pdev) /* make sure any delayed work runs */ for (i = 0; i < card->num_rtd; i++) { struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; - run_delayed_work(&rtd->delayed_work); + flush_delayed_work_sync(&rtd->delayed_work); } /* remove and free each DAI */ @@ -1718,7 +1699,7 @@ static int soc_poweroff(struct device *dev) * now, we're shutting down so no imminent restart. */ for (i = 0; i < card->num_rtd; i++) { struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; - run_delayed_work(&rtd->delayed_work); + flush_delayed_work_sync(&rtd->delayed_work); } snd_soc_dapm_shutdown(card); -- cgit v1.2.3 From 7d8316df44053687625eef792d53b3ac62e82248 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Dec 2010 17:03:27 +0000 Subject: ASoC: Fix AC'97 registration unwind soc_unregister_ac97_dai_link() takes a CODEC as an argument, not a rtd like the registration function, so give it what it's looking for. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 68edc693a8a5..1dc4b11c1988 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1830,7 +1830,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name); while (--i >= 0) - soc_unregister_ac97_dai_link(&card->rtd[i]); + soc_unregister_ac97_dai_link(card->rtd[i].codec); goto probe_aux_dev_err; } } -- cgit v1.2.3 From 8ddab3f5107c3955e70e87a632d4d179ddba1189 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 14 Dec 2010 12:18:30 +0200 Subject: ASoC: Move DAPM paths from DAPM context to snd_soc_card Decoupling DAPM paths from DAPM context is a first prerequisite when extending ASoC core to cross-device paths. This patch is almost a nullop and does not allow to construct cross-device setup but the path clean-up part in dapm_free_widgets is prepared to remove cross-device paths between a device being removed and others. Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1dc4b11c1988..bdb2ca9da58b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1879,6 +1879,7 @@ static int soc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&card->dai_dev_list); INIT_LIST_HEAD(&card->codec_dev_list); INIT_LIST_HEAD(&card->platform_dev_list); + INIT_LIST_HEAD(&card->paths); soc_init_card_debugfs(card); @@ -3481,7 +3482,6 @@ int snd_soc_register_codec(struct device *dev, codec->compress_type = SND_SOC_FLAT_COMPRESSION; INIT_LIST_HEAD(&codec->dapm.widgets); - INIT_LIST_HEAD(&codec->dapm.paths); codec->write = codec_drv->write; codec->read = codec_drv->read; codec->dapm.bias_level = SND_SOC_BIAS_OFF; -- cgit v1.2.3 From 97c866defc0fc6e18b49603ac19f732f53e79c46 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 14 Dec 2010 12:18:31 +0200 Subject: 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 Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bdb2ca9da58b..bd183a7ed696 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1879,6 +1879,7 @@ static int soc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&card->dai_dev_list); INIT_LIST_HEAD(&card->codec_dev_list); INIT_LIST_HEAD(&card->platform_dev_list); + INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->paths); soc_init_card_debugfs(card); @@ -3481,7 +3482,6 @@ int snd_soc_register_codec(struct device *dev, else codec->compress_type = SND_SOC_FLAT_COMPRESSION; - INIT_LIST_HEAD(&codec->dapm.widgets); codec->write = codec_drv->write; codec->read = codec_drv->read; codec->dapm.bias_level = SND_SOC_BIAS_OFF; -- cgit v1.2.3 From 7be31be880ee00c6f8d38184368e8a834923b469 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 14 Dec 2010 12:18:32 +0200 Subject: ASoC: Extend DAPM to handle power changes on cross-device paths Power change event like stream start/stop or kcontrol change in a cross-device path originates from one device but codec bias and widget power changes must be populated to another devices on that path as well. This patch modifies the dapm_power_widgets so that all the widgets on a sound card are checked for a power change, not just those that are specific to originating device. Also bias management is extended to check all the devices. Only exception in bias management are widgetless codecs whose bias state is changed only if power change is originating from that context. DAPM context test is added to dapm_seq_run to take care of if power sequence extends to an another device which requires separate register writes. Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bd183a7ed696..a233607a73c6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1427,6 +1427,7 @@ static int soc_probe_codec(struct snd_soc_card *card, /* mark codec as probed and add to card codec list */ codec->probed = 1; list_add(&codec->card_list, &card->codec_dev_list); + list_add(&codec->dapm.list, &card->dapm_list); return ret; } @@ -1881,6 +1882,7 @@ static int soc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&card->platform_dev_list); INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->paths); + INIT_LIST_HEAD(&card->dapm_list); soc_init_card_debugfs(card); -- cgit v1.2.3 From f6c2ed5dd6ab43447dacc136585fc894e3f3a82d Mon Sep 17 00:00:00 2001 From: Harsha Priya Date: Wed, 5 Jan 2011 11:34:51 +0530 Subject: ASoC: Fix the device references to codec and platform drivers The soc-core takes the platform and codec driver reference during probe. Few of these references are not released during remove. This cause the platform and codec driver module unload to fail. This patch fixes by the taking only one reference to platform and codec module during probe and releases them correctly during remove. This allows load/unload properly Signed-off-by: Vinod Koul Signed-off-by: Harsha Priya Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a233607a73c6..bac7291b6ff6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1259,9 +1259,6 @@ find_codec: if (!strcmp(codec->name, dai_link->codec_name)) { rtd->codec = codec; - if (!try_module_get(codec->dev->driver->owner)) - return -ENODEV; - /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/ list_for_each_entry(codec_dai, &dai_list, list) { if (codec->dev == codec_dai->dev && @@ -1287,10 +1284,6 @@ find_platform: /* no, then find CPU DAI from registered DAIs*/ list_for_each_entry(platform, &platform_list, list) { if (!strcmp(platform->name, dai_link->platform_name)) { - - if (!try_module_get(platform->dev->driver->owner)) - return -ENODEV; - rtd->platform = platform; goto out; } @@ -1425,6 +1418,9 @@ static int soc_probe_codec(struct snd_soc_card *card, soc_init_codec_debugfs(codec); /* mark codec as probed and add to card codec list */ + if (!try_module_get(codec->dev->driver->owner)) + return -ENODEV; + codec->probed = 1; list_add(&codec->card_list, &card->codec_dev_list); list_add(&codec->dapm.list, &card->dapm_list); @@ -1556,6 +1552,10 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) } } /* mark platform as probed and add to card platform list */ + + if (!try_module_get(platform->dev->driver->owner)) + return -ENODEV; + platform->probed = 1; list_add(&platform->card_list, &card->platform_dev_list); } -- cgit v1.2.3