diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 673 |
1 files changed, 286 insertions, 387 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d4bfd4a9076f..3d8cff629a18 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -270,79 +270,54 @@ static const struct file_operations codec_reg_fops = { .llseek = default_llseek, }; -static struct dentry *soc_debugfs_create_dir(struct dentry *parent, - const char *fmt, ...) +static void soc_init_component_debugfs(struct snd_soc_component *component) { - struct dentry *de; - va_list ap; - char *s; + if (component->debugfs_prefix) { + char *name; - va_start(ap, fmt); - s = kvasprintf(GFP_KERNEL, fmt, ap); - va_end(ap); + name = kasprintf(GFP_KERNEL, "%s:%s", + component->debugfs_prefix, component->name); + if (name) { + component->debugfs_root = debugfs_create_dir(name, + component->card->debugfs_card_root); + kfree(name); + } + } else { + component->debugfs_root = debugfs_create_dir(component->name, + component->card->debugfs_card_root); + } - if (!s) - return NULL; + if (!component->debugfs_root) { + dev_warn(component->dev, + "ASoC: Failed to create component debugfs directory\n"); + return; + } - de = debugfs_create_dir(s, parent); - kfree(s); + snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), + component->debugfs_root); - return de; + if (component->init_debugfs) + component->init_debugfs(component); } -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) +static void soc_cleanup_component_debugfs(struct snd_soc_component *component) { - struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root; + debugfs_remove_recursive(component->debugfs_root); +} - codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root, - "codec:%s", - codec->component.name); - if (!codec->debugfs_codec_root) { - dev_warn(codec->dev, - "ASoC: Failed to create codec debugfs directory\n"); - return; - } +static void soc_init_codec_debugfs(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root, + debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, &codec->cache_sync); - debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root, - &codec->cache_only); codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - codec->debugfs_codec_root, + codec->component.debugfs_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) dev_warn(codec->dev, "ASoC: Failed to create codec register debugfs file\n"); - - snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove_recursive(codec->debugfs_codec_root); -} - -static void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ - struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root; - - platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root, - "platform:%s", - platform->component.name); - if (!platform->debugfs_platform_root) { - dev_warn(platform->dev, - "ASoC: Failed to create platform debugfs directory\n"); - return; - } - - snd_soc_dapm_debugfs_init(&platform->component.dapm, - platform->debugfs_platform_root); -} - -static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) -{ - debugfs_remove_recursive(platform->debugfs_platform_root); } static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, @@ -474,19 +449,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) #else -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ -} - -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ -} +#define soc_init_codec_debugfs NULL -static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform) +static inline void soc_init_component_debugfs( + struct snd_soc_component *component) { } -static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) +static inline void soc_cleanup_component_debugfs( + struct snd_soc_component *component) { } @@ -579,10 +550,8 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_codec *codec; int i, j; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* Due to the resume being scheduled into a workqueue we could @@ -668,7 +637,7 @@ int snd_soc_suspend(struct device *dev) 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) { + if (!codec->suspended) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: /* @@ -682,8 +651,10 @@ int snd_soc_suspend(struct device *dev) "ASoC: idle_bias_off CODEC on over suspend\n"); break; } + case SND_SOC_BIAS_OFF: - codec->driver->suspend(codec); + if (codec->driver->suspend) + codec->driver->suspend(codec); codec->suspended = 1; codec->cache_sync = 1; if (codec->component.regmap) @@ -757,11 +728,12 @@ static void soc_resume_deferred(struct work_struct *work) * left with bias OFF or STANDBY and suspended so we must now * resume. Otherwise the suspend was suppressed. */ - if (codec->driver->resume && codec->suspended) { + if (codec->suspended) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_OFF: - codec->driver->resume(codec); + if (codec->driver->resume) + codec->driver->resume(codec); codec->suspended = 0; break; default: @@ -835,10 +807,8 @@ int snd_soc_resume(struct device *dev) struct snd_soc_card *card = dev_get_drvdata(dev); int i, ac97_control = 0; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* activate pins from sleep state */ @@ -887,35 +857,40 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); static const struct snd_soc_dai_ops null_dai_ops = { }; -static struct snd_soc_codec *soc_find_codec( - const struct device_node *codec_of_node, - const char *codec_name) +static struct snd_soc_component *soc_find_component( + const struct device_node *of_node, const char *name) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; - list_for_each_entry(codec, &codec_list, list) { - if (codec_of_node) { - if (codec->dev->of_node != codec_of_node) - continue; - } else { - if (strcmp(codec->component.name, codec_name)) - continue; + list_for_each_entry(component, &component_list, list) { + if (of_node) { + if (component->dev->of_node == of_node) + return component; + } else if (strcmp(component->name, name) == 0) { + return component; } - - return codec; } return NULL; } -static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, - const char *codec_dai_name) +static struct snd_soc_dai *snd_soc_find_dai( + const struct snd_soc_dai_link_component *dlc) { - struct snd_soc_dai *codec_dai; + struct snd_soc_component *component; + struct snd_soc_dai *dai; + + /* Find CPU DAI from registered DAIs*/ + list_for_each_entry(component, &component_list, list) { + if (dlc->of_node && component->dev->of_node != dlc->of_node) + continue; + if (dlc->name && strcmp(dev_name(component->dev), dlc->name)) + continue; + list_for_each_entry(dai, &component->dai_list, list) { + if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) + continue; - list_for_each_entry(codec_dai, &codec->component.dai_list, list) { - if (!strcmp(codec_dai->name, codec_dai_name)) { - return codec_dai; + return dai; } } @@ -926,33 +901,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_component *component; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_platform *platform; - struct snd_soc_dai *cpu_dai; const char *platform_name; int i; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); - /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { - if (dai_link->cpu_of_node && - component->dev->of_node != dai_link->cpu_of_node) - continue; - if (dai_link->cpu_name && - strcmp(dev_name(component->dev), dai_link->cpu_name)) - continue; - list_for_each_entry(cpu_dai, &component->dai_list, list) { - if (dai_link->cpu_dai_name && - strcmp(cpu_dai->name, dai_link->cpu_dai_name)) - continue; - - rtd->cpu_dai = cpu_dai; - } - } - + cpu_dai_component.name = dai_link->cpu_name; + cpu_dai_component.of_node = dai_link->cpu_of_node; + cpu_dai_component.dai_name = dai_link->cpu_dai_name; + rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); @@ -963,15 +924,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) /* Find CODEC from registered CODECs */ for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_codec *codec; - codec = soc_find_codec(codecs[i].of_node, codecs[i].name); - if (!codec) { - dev_err(card->dev, "ASoC: CODEC %s not registered\n", - codecs[i].name); - return -EPROBE_DEFER; - } - - codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name); + codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); @@ -1012,68 +965,46 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return 0; } -static int soc_remove_platform(struct snd_soc_platform *platform) +static void soc_remove_component(struct snd_soc_component *component) { - int ret; - - if (platform->driver->remove) { - ret = platform->driver->remove(platform); - if (ret < 0) - dev_err(platform->dev, "ASoC: failed to remove %d\n", - ret); - } - - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&platform->component.dapm); - - soc_cleanup_platform_debugfs(platform); - platform->probed = 0; - module_put(platform->dev->driver->owner); - - return 0; -} + if (!component->probed) + return; -static void soc_remove_codec(struct snd_soc_codec *codec) -{ - int err; + /* This is a HACK and will be removed soon */ + if (component->codec) + list_del(&component->codec->card_list); - if (codec->driver->remove) { - err = codec->driver->remove(codec); - if (err < 0) - dev_err(codec->dev, "ASoC: failed to remove %d\n", err); - } + if (component->remove) + component->remove(component); - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&codec->dapm); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - soc_cleanup_codec_debugfs(codec); - codec->probed = 0; - list_del(&codec->card_list); - module_put(codec->dev->driver->owner); + soc_cleanup_component_debugfs(component); + component->probed = 0; + module_put(component->dev->driver->owner); } -static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) +static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (codec_dai && codec_dai->probed && - codec_dai->driver->remove_order == order) { - if (codec_dai->driver->remove) { - err = codec_dai->driver->remove(codec_dai); + if (dai && dai->probed && + dai->driver->remove_order == order) { + if (dai->driver->remove) { + err = dai->driver->remove(dai); if (err < 0) - dev_err(codec_dai->dev, + dev_err(dai->dev, "ASoC: failed to remove %s: %d\n", - codec_dai->name, err); + dai->name, err); } - codec_dai->probed = 0; + dai->probed = 0; } } static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int i, err; + int i; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1085,22 +1016,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) /* remove the CODEC DAI */ for (i = 0; i < rtd->num_codecs; i++) - soc_remove_codec_dai(rtd->codec_dais[i], order); + soc_remove_dai(rtd->codec_dais[i], order); - /* remove the cpu_dai */ - if (cpu_dai && cpu_dai->probed && - cpu_dai->driver->remove_order == order) { - if (cpu_dai->driver->remove) { - err = cpu_dai->driver->remove(cpu_dai); - if (err < 0) - dev_err(cpu_dai->dev, - "ASoC: failed to remove %s: %d\n", - cpu_dai->name, err); - } - cpu_dai->probed = 0; - if (!cpu_dai->codec) - module_put(cpu_dai->dev->driver->owner); - } + soc_remove_dai(rtd->cpu_dai, order); } static void soc_remove_link_components(struct snd_soc_card *card, int num, @@ -1109,29 +1027,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int i; /* remove the platform */ - if (platform && platform->probed && - platform->driver->remove_order == order) { - soc_remove_platform(platform); - } + if (platform && platform->component.driver->remove_order == order) + soc_remove_component(&platform->component); /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { - codec = rtd->codec_dais[i]->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + component = rtd->codec_dais[i]->component; + if (component->driver->remove_order == order) + soc_remove_component(component); } /* remove any CPU-side CODEC */ if (cpu_dai) { - codec = cpu_dai->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + if (cpu_dai->component->driver->remove_order == order) + soc_remove_component(cpu_dai->component); } } @@ -1173,137 +1086,78 @@ 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) +static int soc_probe_component(struct snd_soc_card *card, + struct snd_soc_component *component) { - int ret = 0; - const struct snd_soc_codec_driver *driver = codec->driver; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct snd_soc_dai *dai; + int ret; + + if (component->probed) + return 0; - codec->component.card = card; - codec->dapm.card = card; - soc_set_name_prefix(card, &codec->component); + component->card = card; + dapm->card = card; + soc_set_name_prefix(card, component); - if (!try_module_get(codec->dev->driver->owner)) + if (!try_module_get(component->dev->driver->owner)) return -ENODEV; - soc_init_codec_debugfs(codec); + soc_init_component_debugfs(component); - if (driver->dapm_widgets) { - ret = snd_soc_dapm_new_controls(&codec->dapm, - driver->dapm_widgets, - driver->num_dapm_widgets); + if (component->dapm_widgets) { + ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, + component->num_dapm_widgets); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to create new controls %d\n", ret); goto err_probe; } } - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &codec->component.dai_list, list) { - ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); - + list_for_each_entry(dai, &component->dai_list, list) { + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to create DAI widgets %d\n", ret); goto err_probe; } } - codec->dapm.idle_bias_off = driver->idle_bias_off; - - if (driver->probe) { - ret = driver->probe(codec); + if (component->probe) { + ret = component->probe(component); if (ret < 0) { - dev_err(codec->dev, - "ASoC: failed to probe CODEC %d\n", ret); + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); goto err_probe; } - 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->component.name); - } - - if (driver->controls) - snd_soc_add_codec_controls(codec, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, - driver->num_dapm_routes); - - /* 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 0; - -err_probe: - soc_cleanup_codec_debugfs(codec); - module_put(codec->dev->driver->owner); - - return ret; -} - -static int soc_probe_platform(struct snd_soc_card *card, - struct snd_soc_platform *platform) -{ - int ret = 0; - const struct snd_soc_platform_driver *driver = platform->driver; - struct snd_soc_component *component; - struct snd_soc_dai *dai; - - platform->component.card = card; - platform->component.dapm.card = card; - - if (!try_module_get(platform->dev->driver->owner)) - return -ENODEV; - - soc_init_platform_debugfs(platform); - - if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&platform->component.dapm, - driver->dapm_widgets, driver->num_dapm_widgets); - - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(component, &component_list, list) { - if (component->dev != platform->dev) - continue; - list_for_each_entry(dai, &component->dai_list, list) - snd_soc_dapm_new_dai_widgets(&platform->component.dapm, - dai); + WARN(dapm->idle_bias_off && + dapm->bias_level != SND_SOC_BIAS_OFF, + "codec %s can not start from non-off bias with idle_bias_off==1\n", + component->name); } - platform->component.dapm.idle_bias_off = 1; - - if (driver->probe) { - ret = driver->probe(platform); - if (ret < 0) { - dev_err(platform->dev, - "ASoC: failed to probe platform %d\n", ret); - goto err_probe; - } - } + if (component->controls) + snd_soc_add_component_controls(component, component->controls, + component->num_controls); + if (component->dapm_routes) + snd_soc_dapm_add_routes(dapm, component->dapm_routes, + component->num_dapm_routes); - if (driver->controls) - snd_soc_add_platform_controls(platform, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&platform->component.dapm, - driver->dapm_routes, driver->num_dapm_routes); + component->probed = 1; + list_add(&dapm->list, &card->dapm_list); - /* mark platform as probed and add to card platform list */ - platform->probed = 1; - list_add(&platform->component.dapm.list, &card->dapm_list); + /* This is a HACK and will be removed soon */ + if (component->codec) + list_add(&component->codec->card_list, &card->codec_dev_list); return 0; err_probe: - soc_cleanup_platform_debugfs(platform); - module_put(platform->dev->driver->owner); + soc_cleanup_component_debugfs(component); + module_put(component->dev->driver->owner); return ret; } @@ -1325,7 +1179,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, device_initialize(rtd->dev); rtd->dev->parent = rtd->card->dev; rtd->dev->release = rtd_release; - rtd->dev->init_name = name; + dev_set_name(rtd->dev, "%s", name); dev_set_drvdata(rtd->dev, rtd); mutex_init(&rtd->pcm_mutex); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); @@ -1342,17 +1196,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, } rtd->dev_registered = 1; - /* add DAPM sysfs entries for this codec */ - ret = snd_soc_dapm_sys_add(rtd->dev); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); + if (rtd->codec) { + /* add DAPM sysfs entries for this codec */ + ret = snd_soc_dapm_sys_add(rtd->dev); + if (ret < 0) + dev_err(rtd->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(rtd->dev, - "ASoC: failed to add codec sysfs files: %d\n", ret); + /* add codec sysfs entries */ + ret = device_create_file(rtd->dev, &dev_attr_codec_reg); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec sysfs files: %d\n", + ret); + } return 0; } @@ -1361,33 +1219,31 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; int i, ret; /* probe the CPU-side component, if it is a CODEC */ - if (cpu_dai->codec && - !cpu_dai->codec->probed && - cpu_dai->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, cpu_dai->codec); + component = rtd->cpu_dai->component; + if (component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->codec->probed && - rtd->codec_dais[i]->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, rtd->codec_dais[i]->codec); + component = rtd->codec_dais[i]->component; + if (component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } } /* probe the platform */ - if (!platform->probed && - platform->driver->probe_order == order) { - ret = soc_probe_platform(card, platform); + if (platform->component.driver->probe_order == order) { + ret = soc_probe_component(card, &platform->component); if (ret < 0) return ret; } @@ -1482,18 +1338,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) /* probe the cpu_dai */ if (!cpu_dai->probed && cpu_dai->driver->probe_order == order) { - if (!cpu_dai->codec) { - if (!try_module_get(cpu_dai->dev->driver->owner)) - return -ENODEV; - } - if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: failed to probe CPU DAI %s: %d\n", cpu_dai->name, ret); - module_put(cpu_dai->dev->driver->owner); return ret; } } @@ -1654,17 +1504,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *codecname = aux_dev->codec_name; + const char *name = aux_dev->codec_name; - rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname); - if (!rtd->codec) { + rtd->component = soc_find_component(aux_dev->codec_of_node, name); + if (!rtd->component) { if (aux_dev->codec_of_node) - codecname = of_node_full_name(aux_dev->codec_of_node); + name = of_node_full_name(aux_dev->codec_of_node); - dev_err(card->dev, "ASoC: %s not registered\n", codecname); + dev_err(card->dev, "ASoC: %s not registered\n", name); return -EPROBE_DEFER; } + /* + * Some places still reference rtd->codec, so we have to keep that + * initialized if the component is a CODEC. Once all those references + * have been removed, this code can be removed as well. + */ + rtd->codec = rtd->component->codec; + return 0; } @@ -1674,18 +1531,13 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->codec->probed) { - dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); - return -EBUSY; - } - - ret = soc_probe_codec(card, rtd->codec); + ret = soc_probe_component(card, rtd->component); if (ret < 0) return ret; /* do machine specific initialization */ if (aux_dev->init) { - ret = aux_dev->init(&rtd->codec->dapm); + ret = aux_dev->init(rtd->component); if (ret < 0) { dev_err(card->dev, "ASoC: failed to init %s: %d\n", aux_dev->name, ret); @@ -1699,7 +1551,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) 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; + struct snd_soc_component *component = rtd->component; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1708,8 +1560,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (codec && codec->probed) - soc_remove_codec(codec); + if (component && component->probed) + soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -2107,19 +1959,14 @@ static struct platform_driver soc_driver = { int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num) { - mutex_lock(&codec->mutex); - codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); - if (codec->ac97 == NULL) { - mutex_unlock(&codec->mutex); + if (codec->ac97 == NULL) return -ENOMEM; - } codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); if (codec->ac97->bus == NULL) { kfree(codec->ac97); codec->ac97 = NULL; - mutex_unlock(&codec->mutex); return -ENOMEM; } @@ -2132,7 +1979,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, */ codec->ac97_created = 1; - mutex_unlock(&codec->mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); @@ -2302,7 +2148,6 @@ EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); */ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) { - mutex_lock(&codec->mutex); #ifdef CONFIG_SND_SOC_AC97_BUS soc_unregister_ac97_codec(codec); #endif @@ -2310,7 +2155,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) kfree(codec->ac97); codec->ac97 = NULL; codec->ac97_created = 0; - mutex_unlock(&codec->mutex); } EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); @@ -3027,9 +2871,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, unsigned int val, val_mask; int ret; - val = ((ucontrol->value.integer.value[0] + min) & mask); if (invert) - val = max - val; + val = (max - ucontrol->value.integer.value[0]) & mask; + else + val = ((ucontrol->value.integer.value[0] + min) & mask); val_mask = mask << shift; val = val << shift; @@ -3038,9 +2883,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, return ret; if (snd_soc_volsw_is_stereo(mc)) { - val = ((ucontrol->value.integer.value[1] + min) & mask); if (invert) - val = max - val; + val = (max - ucontrol->value.integer.value[1]) & mask; + else + val = ((ucontrol->value.integer.value[1] + min) & mask); val_mask = mask << shift; val = val << shift; @@ -3085,8 +2931,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, if (invert) ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[0] = - ucontrol->value.integer.value[0] - min; + else + ucontrol->value.integer.value[0] = + ucontrol->value.integer.value[0] - min; if (snd_soc_volsw_is_stereo(mc)) { ret = snd_soc_component_read(component, rreg, &val); @@ -3097,8 +2944,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, if (invert) ucontrol->value.integer.value[1] = max - ucontrol->value.integer.value[1]; - ucontrol->value.integer.value[1] = - ucontrol->value.integer.value[1] - min; + else + ucontrol->value.integer.value[1] = + ucontrol->value.integer.value[1] - min; } return 0; @@ -3203,7 +3051,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, unsigned int val, mask; void *data; - if (!component->regmap) + if (!component->regmap || !params->num_regs) return -EINVAL; len = params->num_regs * component->val_bytes; @@ -3928,8 +3776,11 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); */ int snd_soc_unregister_card(struct snd_soc_card *card) { - if (card->instantiated) + if (card->instantiated) { + card->instantiated = false; + snd_soc_dapm_shutdown(card); soc_cleanup_card_resources(card); + } dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; @@ -4116,6 +3967,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver; + component->probe = component->driver->probe; + component->remove = component->driver->remove; if (!component->dapm_ptr) component->dapm_ptr = &component->dapm; @@ -4124,19 +3977,42 @@ 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 = true; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; + component->controls = driver->controls; + component->num_controls = driver->num_controls; + component->dapm_widgets = driver->dapm_widgets; + component->num_dapm_widgets = driver->num_dapm_widgets; + component->dapm_routes = driver->dapm_routes; + component->num_dapm_routes = driver->num_dapm_routes; + INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); return 0; } +static void snd_soc_component_init_regmap(struct snd_soc_component *component) +{ + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, NULL); + if (component->regmap) { + int val_bytes = regmap_get_val_bytes(component->regmap); + /* Errors are legitimate for non-integer byte multiples */ + if (val_bytes > 0) + component->val_bytes = val_bytes; + } +} + static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { + if (!component->write && !component->read) + snd_soc_component_init_regmap(component); + list_add(&component->list, &component_list); } @@ -4225,22 +4101,18 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); -static int snd_soc_platform_drv_write(struct snd_soc_component *component, - unsigned int reg, unsigned int val) +static int snd_soc_platform_drv_probe(struct snd_soc_component *component) { struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - return platform->driver->write(platform, reg, val); + return platform->driver->probe(platform); } -static int snd_soc_platform_drv_read(struct snd_soc_component *component, - unsigned int reg, unsigned int *val) +static void snd_soc_platform_drv_remove(struct snd_soc_component *component) { struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - *val = platform->driver->read(platform, reg); - - return 0; + platform->driver->remove(platform); } /** @@ -4261,10 +4133,15 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->dev = dev; platform->driver = platform_drv; - if (platform_drv->write) - platform->component.write = snd_soc_platform_drv_write; - if (platform_drv->read) - platform->component.read = snd_soc_platform_drv_read; + + if (platform_drv->probe) + platform->component.probe = snd_soc_platform_drv_probe; + if (platform_drv->remove) + platform->component.remove = snd_soc_platform_drv_remove; + +#ifdef CONFIG_DEBUG_FS + platform->component.debugfs_prefix = "platform"; +#endif mutex_lock(&client_mutex); snd_soc_component_add_unlocked(&platform->component); @@ -4386,6 +4263,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) stream->formats |= codec_format_map[i]; } +static int snd_soc_codec_drv_probe(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->probe(codec); +} + +static void snd_soc_codec_drv_remove(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + codec->driver->remove(codec); +} + static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -4424,7 +4315,6 @@ int snd_soc_register_codec(struct device *dev, { struct snd_soc_codec *codec; struct snd_soc_dai *dai; - struct regmap *regmap; int ret, i; dev_dbg(dev, "codec register %s\n", dev_name(dev)); @@ -4434,18 +4324,37 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; codec->component.dapm_ptr = &codec->dapm; + codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, |