These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / sound / soc / soc-core.c
index 2373252..a1305f8 100644 (file)
@@ -40,6 +40,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dpcm.h>
+#include <sound/soc-topology.h>
 #include <sound/initval.h>
 
 #define CREATE_TRACE_POINTS
@@ -92,30 +93,21 @@ static int format_register_str(struct snd_soc_codec *codec,
        int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
        int regsize = codec->driver->reg_word_size * 2;
        int ret;
-       char tmpbuf[len + 1];
-       char regbuf[regsize + 1];
-
-       /* since tmpbuf is allocated on the stack, warn the callers if they
-        * try to abuse this function */
-       WARN_ON(len > 63);
 
        /* +2 for ': ' and + 1 for '\n' */
        if (wordsize + regsize + 2 + 1 != len)
                return -EINVAL;
 
-       ret = snd_soc_read(codec, reg);
-       if (ret < 0) {
-               memset(regbuf, 'X', regsize);
-               regbuf[regsize] = '\0';
-       } else {
-               snprintf(regbuf, regsize + 1, "%.*x", regsize, ret);
-       }
-
-       /* prepare the buffer */
-       snprintf(tmpbuf, len + 1, "%.*x: %s\n", wordsize, reg, regbuf);
-       /* copy it back to the caller without the '\0' */
-       memcpy(buf, tmpbuf, len);
+       sprintf(buf, "%.*x: ", wordsize, reg);
+       buf += wordsize + 2;
 
+       ret = snd_soc_read(codec, reg);
+       if (ret < 0)
+               memset(buf, 'X', regsize);
+       else
+               sprintf(buf, "%.*x", regsize, ret);
+       buf[regsize] = '\n';
+       /* no NUL-termination needed */
        return 0;
 }
 
@@ -662,10 +654,12 @@ int snd_soc_suspend(struct device *dev)
 
        /* suspend all CODECs */
        list_for_each_entry(codec, &card->codec_dev_list, card_list) {
+               struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
                /* If there are paths active then the CODEC will be held with
                 * bias _ON and should not be suspended. */
                if (!codec->suspended) {
-                       switch (codec->dapm.bias_level) {
+                       switch (snd_soc_dapm_get_bias_level(dapm)) {
                        case SND_SOC_BIAS_STANDBY:
                                /*
                                 * If the CODEC is capable of idle
@@ -673,7 +667,7 @@ int snd_soc_suspend(struct device *dev)
                                 * means it's doing something,
                                 * otherwise fall through.
                                 */
-                               if (codec->dapm.idle_bias_off) {
+                               if (dapm->idle_bias_off) {
                                        dev_dbg(codec->dev,
                                                "ASoC: idle_bias_off CODEC on over suspend\n");
                                        break;
@@ -750,23 +744,10 @@ static void soc_resume_deferred(struct work_struct *work)
        }
 
        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.
-                */
                if (codec->suspended) {
-                       switch (codec->dapm.bias_level) {
-                       case SND_SOC_BIAS_STANDBY:
-                       case SND_SOC_BIAS_OFF:
-                               if (codec->driver->resume)
-                                       codec->driver->resume(codec);
-                               codec->suspended = 0;
-                               break;
-                       default:
-                               dev_dbg(codec->dev,
-                                       "ASoC: CODEC was on over suspend\n");
-                               break;
-                       }
+                       if (codec->driver->resume)
+                               codec->driver->resume(codec);
+                       codec->suspended = 0;
                }
        }
 
@@ -814,12 +795,12 @@ static void soc_resume_deferred(struct work_struct *work)
 
        dev_dbg(card->dev, "ASoC: resume work completed\n");
 
-       /* userspace can access us now we are back as we were before */
-       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
-
        /* Recheck all endpoints too, their state is affected by suspend */
        dapm_mark_endpoints_dirty(card);
        snd_soc_dapm_sync(&card->dapm);
+
+       /* userspace can access us now we are back as we were before */
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
 }
 
 /* powers up audio subsystem after a suspend */
@@ -904,12 +885,17 @@ static struct snd_soc_dai *snd_soc_find_dai(
 {
        struct snd_soc_component *component;
        struct snd_soc_dai *dai;
+       struct device_node *component_of_node;
 
        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)
+               component_of_node = component->dev->of_node;
+               if (!component_of_node && component->dev->parent)
+                       component_of_node = component->dev->parent->of_node;
+
+               if (dlc->of_node && component_of_node != dlc->of_node)
                        continue;
                if (dlc->name && strcmp(component->name, dlc->name))
                        continue;
@@ -994,7 +980,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 
 static void soc_remove_component(struct snd_soc_component *component)
 {
-       if (!component->probed)
+       if (!component->card)
                return;
 
        /* This is a HACK and will be removed soon */
@@ -1007,7 +993,7 @@ static void soc_remove_component(struct snd_soc_component *component)
        snd_soc_dapm_free(snd_soc_component_get_dapm(component));
 
        soc_cleanup_component_debugfs(component);
-       component->probed = 0;
+       component->card = NULL;
        module_put(component->dev->driver->owner);
 }
 
@@ -1118,16 +1104,26 @@ static int soc_probe_component(struct snd_soc_card *card,
        struct snd_soc_dai *dai;
        int ret;
 
-       if (component->probed)
+       if (!strcmp(component->name, "snd-soc-dummy"))
                return 0;
 
-       component->card = card;
-       dapm->card = card;
-       soc_set_name_prefix(card, component);
+       if (component->card) {
+               if (component->card != card) {
+                       dev_err(component->dev,
+                               "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n",
+                               card->name, component->card->name);
+                       return -ENODEV;
+               }
+               return 0;
+       }
 
        if (!try_module_get(component->dev->driver->owner))
                return -ENODEV;
 
+       component->card = card;
+       dapm->card = card;
+       soc_set_name_prefix(card, component);
+
        soc_init_component_debugfs(component);
 
        if (component->dapm_widgets) {
@@ -1171,7 +1167,6 @@ static int soc_probe_component(struct snd_soc_card *card,
                snd_soc_dapm_add_routes(dapm, component->dapm_routes,
                                        component->num_dapm_routes);
 
-       component->probed = 1;
        list_add(&dapm->list, &card->dapm_list);
 
        /* This is a HACK and will be removed soon */
@@ -1182,6 +1177,7 @@ static int soc_probe_component(struct snd_soc_card *card,
 
 err_probe:
        soc_cleanup_component_debugfs(component);
+       component->card = NULL;
        module_put(component->dev->driver->owner);
 
        return ret;
@@ -1374,9 +1370,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                soc_dpcm_debugfs_add(rtd);
 #endif
 
-       if (cpu_dai->driver->compress_dai) {
+       if (cpu_dai->driver->compress_new) {
                /*create compress_device"*/
-               ret = soc_new_compress(rtd, num);
+               ret = cpu_dai->driver->compress_new(rtd, num);
                if (ret < 0) {
                        dev_err(card->dev, "ASoC: can't create compress %s\n",
                                         dai_link->stream_name);
@@ -1465,7 +1461,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
                rtd->dev_registered = 0;
        }
 
-       if (component && component->probed)
+       if (component)
                soc_remove_component(component);
 }
 
@@ -1732,6 +1728,7 @@ card_probe_error:
        if (card->remove)
                card->remove(card);
 
+       snd_soc_dapm_free(&card->dapm);
        soc_cleanup_card_debugfs(card);
        snd_card_free(card->snd_card);
 
@@ -2143,7 +2140,7 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
 /**
  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
  * @dai: DAI
- * @ratio Ratio of BCLK to Sample rate.
+ * @ratio: Ratio of BCLK to Sample rate.
  *
  * Configures the DAI for a preset BCLK to sample rate ratio.
  */
@@ -2435,6 +2432,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
                card->rtd_aux[i].card = card;
 
        INIT_LIST_HEAD(&card->dapm_dirty);
+       INIT_LIST_HEAD(&card->dobj_list);
        card->instantiated = 0;
        mutex_init(&card->mutex);
        mutex_init(&card->dapm_mutex);
@@ -2599,7 +2597,8 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
                 * the same naming style even though those DAIs are not
                 * component-less anymore.
                 */
-               if (count == 1 && legacy_dai_naming) {
+               if (count == 1 && legacy_dai_naming &&
+                       (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) {
                        dai->name = fmt_single_name(dev, &dai->id);
                } else {
                        dai->name = fmt_multiple_name(dev, &dai_drv[i]);
@@ -2665,10 +2664,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
        component->probe = component->driver->probe;
        component->remove = component->driver->remove;
 
-       if (!component->dapm_ptr)
-               component->dapm_ptr = &component->dapm;
-
-       dapm = component->dapm_ptr;
+       dapm = &component->dapm;
        dapm->dev = dev;
        dapm->component = component;
        dapm->bias_level = SND_SOC_BIAS_OFF;
@@ -2749,6 +2745,7 @@ static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
        }
 
        list_add(&component->list, &component_list);
+       INIT_LIST_HEAD(&component->dobj_list);
 }
 
 static void snd_soc_component_add(struct snd_soc_component *component)
@@ -2811,6 +2808,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_component);
 /**
  * snd_soc_unregister_component - Unregister a component from the ASoC core
  *
+ * @dev: The device to unregister
  */
 void snd_soc_unregister_component(struct device *dev)
 {
@@ -2825,6 +2823,7 @@ void snd_soc_unregister_component(struct device *dev)
        return;
 
 found:
+       snd_soc_tplg_component_remove(cmpnt, SND_SOC_TPLG_INDEX_ALL);
        snd_soc_component_del_unlocked(cmpnt);
        mutex_unlock(&client_mutex);
        snd_soc_component_cleanup(cmpnt);
@@ -2850,7 +2849,7 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
  * snd_soc_add_platform - Add a platform to the ASoC core
  * @dev: The parent device for the platform
  * @platform: The platform to add
- * @platform_driver: The driver for the platform
+ * @platform_drv: The driver for the platform
  */
 int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
                const struct snd_soc_platform_driver *platform_drv)
@@ -2889,7 +2888,8 @@ EXPORT_SYMBOL_GPL(snd_soc_add_platform);
 /**
  * snd_soc_register_platform - Register a platform with the ASoC core
  *
- * @platform: platform to register
+ * @dev: The device for the platform
+ * @platform_drv: The driver for the platform
  */
 int snd_soc_register_platform(struct device *dev,
                const struct snd_soc_platform_driver *platform_drv)
@@ -2950,7 +2950,7 @@ EXPORT_SYMBOL_GPL(snd_soc_lookup_platform);
 /**
  * snd_soc_unregister_platform - Unregister a platform from the ASoC core
  *
- * @platform: platform to unregister
+ * @dev: platform to unregister
  */
 void snd_soc_unregister_platform(struct device *dev)
 {
@@ -3041,13 +3041,17 @@ static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm,
 /**
  * snd_soc_register_codec - Register a codec with the ASoC core
  *
- * @codec: codec to register
+ * @dev: The parent device for this codec
+ * @codec_drv: Codec driver
+ * @dai_drv: The associated DAI driver
+ * @num_dai: Number of DAIs
  */
 int snd_soc_register_codec(struct device *dev,
                           const struct snd_soc_codec_driver *codec_drv,
                           struct snd_soc_dai_driver *dai_drv,
                           int num_dai)
 {
+       struct snd_soc_dapm_context *dapm;
        struct snd_soc_codec *codec;
        struct snd_soc_dai *dai;
        int ret, i;
@@ -3058,7 +3062,6 @@ int snd_soc_register_codec(struct device *dev,
        if (codec == NULL)
                return -ENOMEM;
 
-       codec->component.dapm_ptr = &codec->dapm;
        codec->component.codec = codec;
 
        ret = snd_soc_component_initialize(&codec->component,
@@ -3088,12 +3091,14 @@ int snd_soc_register_codec(struct device *dev,
        if (codec_drv->read)
                codec->component.read = snd_soc_codec_drv_read;
        codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
-       codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
-       codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
+
+       dapm = snd_soc_codec_get_dapm(codec);
+       dapm->idle_bias_off = codec_drv->idle_bias_off;
+       dapm->suspend_bias_off = codec_drv->suspend_bias_off;
        if (codec_drv->seq_notifier)
-               codec->dapm.seq_notifier = codec_drv->seq_notifier;
+               dapm->seq_notifier = codec_drv->seq_notifier;
        if (codec_drv->set_bias_level)
-               codec->dapm.set_bias_level = snd_soc_codec_set_bias_level;
+               dapm->set_bias_level = snd_soc_codec_set_bias_level;
        codec->dev = dev;
        codec->driver = codec_drv;
        codec->component.val_bytes = codec_drv->reg_word_size;
@@ -3140,7 +3145,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec);
 /**
  * snd_soc_unregister_codec - Unregister a codec from the ASoC core
  *
- * @codec: codec to unregister
+ * @dev: codec to unregister
  */
 void snd_soc_unregister_codec(struct device *dev)
 {
@@ -3286,13 +3291,38 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
 
+static int snd_soc_of_get_slot_mask(struct device_node *np,
+                                   const char *prop_name,
+                                   unsigned int *mask)
+{
+       u32 val;
+       const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
+       int i;
+
+       if (!of_slot_mask)
+               return 0;
+       val /= sizeof(u32);
+       for (i = 0; i < val; i++)
+               if (be32_to_cpup(&of_slot_mask[i]))
+                       *mask |= (1 << i);
+
+       return val;
+}
+
 int snd_soc_of_parse_tdm_slot(struct device_node *np,
+                             unsigned int *tx_mask,
+                             unsigned int *rx_mask,
                              unsigned int *slots,
                              unsigned int *slot_width)
 {
        u32 val;
        int ret;
 
+       if (tx_mask)
+               snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", tx_mask);
+       if (rx_mask)
+               snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
+
        if (of_property_read_bool(np, "dai-tdm-slot-num")) {
                ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
                if (ret)
@@ -3315,6 +3345,26 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
 
+void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
+                                  struct snd_soc_codec_conf *codec_conf,
+                                  struct device_node *of_node,
+                                  const char *propname)
+{
+       struct device_node *np = card->dev->of_node;
+       const char *str;
+       int ret;
+
+       ret = of_property_read_string(np, propname, &str);
+       if (ret < 0) {
+               /* no prefix is not error */
+               return;
+       }
+
+       codec_conf->of_node     = of_node;
+       codec_conf->name_prefix = str;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix);
+
 int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname)
 {
@@ -3488,11 +3538,16 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args,
                                const char **dai_name)
 {
        struct snd_soc_component *pos;
+       struct device_node *component_of_node;
        int ret = -EPROBE_DEFER;
 
        mutex_lock(&client_mutex);
        list_for_each_entry(pos, &component_list, list) {
-               if (pos->dev->of_node != args->np)
+               component_of_node = pos->dev->of_node;
+               if (!component_of_node && pos->dev->parent)
+                       component_of_node = pos->dev->parent->of_node;
+
+               if (component_of_node != args->np)
                        continue;
 
                if (pos->driver->of_xlate_dai_name) {