Merge remote-tracking branches 'asoc/topic/link-param', 'asoc/topic/max98090', 'asoc...
[sfrench/cifs-2.6.git] / sound / soc / soc-core.c
index 30579ca5bacb985c7dfa9b9ad30f58cee45d6e1a..12b7ff2426da8867177369a4fd603e322b48baca 100644 (file)
@@ -292,6 +292,9 @@ static const struct file_operations codec_reg_fops = {
 
 static void soc_init_component_debugfs(struct snd_soc_component *component)
 {
+       if (!component->card->debugfs_card_root)
+               return;
+
        if (component->debugfs_prefix) {
                char *name;
 
@@ -347,6 +350,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(codec, &codec_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               codec->component.name);
@@ -358,6 +363,8 @@ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        if (ret >= 0)
                ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
@@ -382,6 +389,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                list_for_each_entry(dai, &component->dai_list, list) {
                        len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
@@ -395,6 +404,8 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -418,6 +429,8 @@ static ssize_t platform_list_read_file(struct file *file,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&client_mutex);
+
        list_for_each_entry(platform, &platform_list, list) {
                len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
                               platform->component.name);
@@ -429,6 +442,8 @@ static ssize_t platform_list_read_file(struct file *file,
                }
        }
 
+       mutex_unlock(&client_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -443,6 +458,9 @@ static const struct file_operations platform_list_fops = {
 
 static void soc_init_card_debugfs(struct snd_soc_card *card)
 {
+       if (!snd_soc_debugfs_root)
+               return;
+
        card->debugfs_card_root = debugfs_create_dir(card->name,
                                                     snd_soc_debugfs_root);
        if (!card->debugfs_card_root) {
@@ -464,6 +482,34 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
        debugfs_remove_recursive(card->debugfs_card_root);
 }
 
+
+static void snd_soc_debugfs_init(void)
+{
+       snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
+       if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
+               pr_warn("ASoC: Failed to create debugfs directory\n");
+               snd_soc_debugfs_root = NULL;
+               return;
+       }
+
+       if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
+                                &codec_list_fops))
+               pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
+
+       if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
+                                &dai_list_fops))
+               pr_warn("ASoC: Failed to create DAI list debugfs file\n");
+
+       if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
+                                &platform_list_fops))
+               pr_warn("ASoC: Failed to create platform list debugfs file\n");
+}
+
+static void snd_soc_debugfs_exit(void)
+{
+       debugfs_remove_recursive(snd_soc_debugfs_root);
+}
+
 #else
 
 #define soc_init_codec_debugfs NULL
@@ -485,6 +531,15 @@ static inline void soc_init_card_debugfs(struct snd_soc_card *card)
 static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
 {
 }
+
+static inline void snd_soc_debugfs_init(void)
+{
+}
+
+static inline void snd_soc_debugfs_exit(void)
+{
+}
+
 #endif
 
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
@@ -583,15 +638,9 @@ int snd_soc_suspend(struct device *dev)
                        cpu_dai->driver->suspend(cpu_dai);
        }
 
-       /* close any waiting streams and save state */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai **codec_dais = card->rtd[i].codec_dais;
+       /* close any waiting streams */
+       for (i = 0; i < card->num_rtd; i++)
                flush_delayed_work(&card->rtd[i].delayed_work);
-               for (j = 0; j < card->rtd[i].num_codecs; j++) {
-                       codec_dais[j]->codec->dapm.suspend_bias_level =
-                                       codec_dais[j]->codec->dapm.bias_level;
-               }
-       }
 
        for (i = 0; i < card->num_rtd; i++) {
 
@@ -836,6 +885,8 @@ static struct snd_soc_component *soc_find_component(
 {
        struct snd_soc_component *component;
 
+       lockdep_assert_held(&client_mutex);
+
        list_for_each_entry(component, &component_list, list) {
                if (of_node) {
                        if (component->dev->of_node == of_node)
@@ -854,6 +905,8 @@ static struct snd_soc_dai *snd_soc_find_dai(
        struct snd_soc_component *component;
        struct snd_soc_dai *dai;
 
+       lockdep_assert_held(&client_mutex);
+
        /* 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)
@@ -1245,7 +1298,8 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
        capture_w = cpu_dai->capture_widget;
        if (play_w && capture_w) {
                ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                          capture_w, play_w);
+                                          dai_link->num_params, capture_w,
+                                          play_w);
                if (ret != 0) {
                        dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
                                play_w->name, capture_w->name, ret);
@@ -1257,7 +1311,8 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
        capture_w = codec_dai->capture_widget;
        if (play_w && capture_w) {
                ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                          capture_w, play_w);
+                                          dai_link->num_params, capture_w,
+                                          play_w);
                if (ret != 0) {
                        dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n",
                                play_w->name, capture_w->name, ret);
@@ -1306,21 +1361,17 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                }
        }
 
+       if (dai_link->dai_fmt)
+               snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt);
+
        ret = soc_post_component_init(rtd, dai_link->name);
        if (ret)
                return ret;
 
 #ifdef CONFIG_DEBUG_FS
        /* add DPCM sysfs entries */
-       if (dai_link->dynamic) {
-               ret = soc_dpcm_debugfs_add(rtd);
-               if (ret < 0) {
-                       dev_err(rtd->dev,
-                               "ASoC: failed to add dpcm sysfs entries: %d\n",
-                               ret);
-                       return ret;
-               }
-       }
+       if (dai_link->dynamic)
+               soc_dpcm_debugfs_add(rtd);
 #endif
 
        if (cpu_dai->driver->compress_dai) {
@@ -1410,7 +1461,6 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
 
        /* 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;
        }
@@ -1508,6 +1558,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        struct snd_soc_codec *codec;
        int ret, i, order;
 
+       mutex_lock(&client_mutex);
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
        /* bind DAIs */
@@ -1543,6 +1594,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                goto base_error;
        }
 
+       soc_init_card_debugfs(card);
+
        card->dapm.bias_level = SND_SOC_BIAS_OFF;
        card->dapm.dev = card->dev;
        card->dapm.card = card;
@@ -1561,6 +1614,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
                                          card->num_dapm_widgets);
 
+       if (card->of_dapm_widgets)
+               snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
+                                         card->num_of_dapm_widgets);
+
        /* initialise the sound card only once */
        if (card->probe) {
                ret = card->probe(card);
@@ -1616,11 +1673,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
                                        card->num_dapm_routes);
 
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].dai_fmt)
-                       snd_soc_runtime_set_dai_fmt(&card->rtd[i],
-                               card->dai_link[i].dai_fmt);
-       }
+       if (card->of_dapm_routes)
+               snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
+                                       card->num_of_dapm_routes);
 
        snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
                 "%s", card->name);
@@ -1662,6 +1717,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        card->instantiated = 1;
        snd_soc_dapm_sync(&card->dapm);
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return 0;
 
@@ -1676,10 +1732,12 @@ card_probe_error:
        if (card->remove)
                card->remove(card);
 
+       soc_cleanup_card_debugfs(card);
        snd_card_free(card->snd_card);
 
 base_error:
        mutex_unlock(&card->mutex);
+       mutex_unlock(&client_mutex);
 
        return ret;
 }
@@ -2353,8 +2411,6 @@ int snd_soc_register_card(struct snd_soc_card *card)
 
        snd_soc_initialize_card_lists(card);
 
-       soc_init_card_debugfs(card);
-
        card->rtd = devm_kzalloc(card->dev,
                                 sizeof(struct snd_soc_pcm_runtime) *
                                 (card->num_links + card->num_aux_devs),
@@ -2385,7 +2441,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
 
        ret = snd_soc_instantiate_card(card);
        if (ret != 0)
-               soc_cleanup_card_debugfs(card);
+               return ret;
 
        /* deactivate pins to sleep state */
        for (i = 0; i < card->num_rtd; i++) {
@@ -2713,13 +2769,6 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component)
        list_del(&component->list);
 }
 
-static void snd_soc_component_del(struct snd_soc_component *component)
-{
-       mutex_lock(&client_mutex);
-       snd_soc_component_del_unlocked(component);
-       mutex_unlock(&client_mutex);
-}
-
 int snd_soc_register_component(struct device *dev,
                               const struct snd_soc_component_driver *cmpnt_drv,
                               struct snd_soc_dai_driver *dai_drv,
@@ -2767,14 +2816,17 @@ void snd_soc_unregister_component(struct device *dev)
 {
        struct snd_soc_component *cmpnt;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(cmpnt, &component_list, list) {
                if (dev == cmpnt->dev && cmpnt->registered_as_component)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-       snd_soc_component_del(cmpnt);
+       snd_soc_component_del_unlocked(cmpnt);
+       mutex_unlock(&client_mutex);
        snd_soc_component_cleanup(cmpnt);
        kfree(cmpnt);
 }
@@ -2882,10 +2934,14 @@ struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
 {
        struct snd_soc_platform *platform;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(platform, &platform_list, list) {
-               if (dev == platform->dev)
+               if (dev == platform->dev) {
+                       mutex_unlock(&client_mutex);
                        return platform;
+               }
        }
+       mutex_unlock(&client_mutex);
 
        return NULL;
 }
@@ -3090,15 +3146,15 @@ void snd_soc_unregister_codec(struct device *dev)
 {
        struct snd_soc_codec *codec;
 
+       mutex_lock(&client_mutex);
        list_for_each_entry(codec, &codec_list, list) {
                if (dev == codec->dev)
                        goto found;
        }
+       mutex_unlock(&client_mutex);
        return;
 
 found:
-
-       mutex_lock(&client_mutex);
        list_del(&codec->list);
        snd_soc_component_del_unlocked(&codec->component);
        mutex_unlock(&client_mutex);
@@ -3223,8 +3279,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
                widgets[i].name = wname;
        }
 
-       card->dapm_widgets = widgets;
-       card->num_dapm_widgets = num_widgets;
+       card->of_dapm_widgets = widgets;
+       card->num_of_dapm_widgets = num_widgets;
 
        return 0;
 }
@@ -3308,8 +3364,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                }
        }
 
-       card->num_dapm_routes = num_routes;
-       card->dapm_routes = routes;
+       card->num_of_dapm_routes = num_routes;
+       card->of_dapm_routes = routes;
 
        return 0;
 }
@@ -3568,26 +3624,7 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
 
 static int __init snd_soc_init(void)
 {
-#ifdef CONFIG_DEBUG_FS
-       snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
-       if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
-               pr_warn("ASoC: Failed to create debugfs directory\n");
-               snd_soc_debugfs_root = NULL;
-       }
-
-       if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
-                                &codec_list_fops))
-               pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
-
-       if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
-                                &dai_list_fops))
-               pr_warn("ASoC: Failed to create DAI list debugfs file\n");
-
-       if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
-                                &platform_list_fops))
-               pr_warn("ASoC: Failed to create platform list debugfs file\n");
-#endif
-
+       snd_soc_debugfs_init();
        snd_soc_util_init();
 
        return platform_driver_register(&soc_driver);
@@ -3597,9 +3634,9 @@ module_init(snd_soc_init);
 static void __exit snd_soc_exit(void)
 {
        snd_soc_util_exit();
+       snd_soc_debugfs_exit();
 
 #ifdef CONFIG_DEBUG_FS
-       debugfs_remove_recursive(snd_soc_debugfs_root);
 #endif
        platform_driver_unregister(&soc_driver);
 }