Merge remote-tracking branch 'asoc/fix/core' into asoc-linus
authorMark Brown <broonie@kernel.org>
Wed, 8 Oct 2014 15:44:49 +0000 (16:44 +0100)
committerMark Brown <broonie@kernel.org>
Wed, 8 Oct 2014 15:44:49 +0000 (16:44 +0100)
1  2 
sound/soc/soc-core.c
sound/soc/soc-pcm.c

diff --combined sound/soc/soc-core.c
@@@ -270,54 -270,79 +270,54 @@@ static const struct file_operations cod
        .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,
@@@ -449,15 -474,19 +449,15 @@@ static void soc_cleanup_card_debugfs(st
  
  #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)
  {
  }
  
@@@ -550,8 -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
        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:
                                /*
                                                "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)
@@@ -728,12 -757,11 +728,12 @@@ static void soc_resume_deferred(struct 
                 * 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:
@@@ -807,8 -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 */
@@@ -857,40 -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;
                }
        }
  
@@@ -901,19 -926,33 +901,19 @@@ static int soc_bind_dai_link(struct snd
  {
        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);
  
        /* 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);
        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) {
  
        /* 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,
        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);
        }
  }
  
@@@ -1086,78 -1173,137 +1086,78 @@@ static void soc_set_name_prefix(struct 
        }
  }
  
 -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;
  }
@@@ -1179,7 -1325,7 +1179,7 @@@ static int soc_post_component_init(stru
        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);
        }
        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;
  }
@@@ -1219,31 -1361,33 +1219,31 @@@ static int soc_probe_link_components(st
                                     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;
        }
@@@ -1338,12 -1482,18 +1338,12 @@@ static int soc_probe_link_dais(struct s
        /* 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;
                        }
                }
@@@ -1504,24 -1654,17 +1504,24 @@@ static int soc_bind_aux_dev(struct snd_
  {
        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;
  }
  
@@@ -1531,13 -1674,18 +1531,13 @@@ static int soc_probe_aux_dev(struct snd
        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);
  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) {
                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)
@@@ -1959,14 -2107,19 +1959,14 @@@ static struct platform_driver soc_drive
  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;
        }
  
         */
        codec->ac97_created = 1;
  
 -      mutex_unlock(&codec->mutex);
        return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
@@@ -2148,6 -2302,7 +2148,6 @@@ EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_
   */
  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
        kfree(codec->ac97);
        codec->ac97 = NULL;
        codec->ac97_created = 0;
 -      mutex_unlock(&codec->mutex);
  }
  EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
  
@@@ -2871,10 -3027,9 +2871,10 @@@ int snd_soc_put_volsw_range(struct snd_
        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;
  
                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;
  
@@@ -2931,9 -3085,8 +2931,9 @@@ int snd_soc_get_volsw_range(struct snd_
        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);
                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;
@@@ -3776,11 -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;
@@@ -3967,8 -4116,6 +3967,8 @@@ static int snd_soc_component_initialize
  
        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;
        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);
  }
  
@@@ -4101,18 -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);
  }
  
  /**
@@@ -4133,15 -4261,10 +4133,15 @@@ int snd_soc_add_platform(struct device 
  
        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);
@@@ -4192,10 -4315,10 +4192,10 @@@ void snd_soc_remove_platform(struct snd
        snd_soc_component_del_unlocked(&platform->component);
        mutex_unlock(&client_mutex);
  
-       snd_soc_component_cleanup(&platform->component);
        dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
                platform->component.name);
+       snd_soc_component_cleanup(&platform->component);
  }
  EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
  
@@@ -4263,20 -4386,6 +4263,20 @@@ static void fixup_codec_formats(struct 
                        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)
  {
@@@ -4315,6 -4424,7 +4315,6 @@@ int snd_soc_register_codec(struct devic
  {
        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));
                return -ENOMEM;
  
        codec->component.dapm_ptr = &codec->dapm;
 +      codec->component.codec = codec;
  
        ret = snd_soc_component_initialize(&codec->component,
                        &codec_drv->component_driver, dev);
        if (ret)
                goto err_free;
  
 +      if (codec_drv->controls) {
 +              codec->component.controls = codec_drv->controls;
 +              codec->component.num_controls = codec_drv->num_controls;
 +      }
 +      if (codec_drv->dapm_widgets) {
 +              codec->component.dapm_widgets = codec_drv->dapm_widgets;
 +              codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
 +      }
 +      if (codec_drv->dapm_routes) {
 +              codec->component.dapm_routes = codec_drv->dapm_routes;
 +              codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
 +      }
 +
 +      if (codec_drv->probe)
 +              codec->component.probe = snd_soc_codec_drv_probe;
 +      if (codec_drv->remove)
 +              codec->component.remove = snd_soc_codec_drv_remove;
        if (codec_drv->write)
                codec->component.write = snd_soc_codec_drv_write;
        if (codec_drv->read)
                codec->component.read = snd_soc_codec_drv_read;
        codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
 -      codec->dapm.codec = codec;
 +      codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
 +      codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
        if (codec_drv->seq_notifier)
                codec->dapm.seq_notifier = codec_drv->seq_notifier;
        if (codec_drv->set_bias_level)
        codec->component.val_bytes = codec_drv->reg_word_size;
        mutex_init(&codec->mutex);
  
 -      if (!codec->component.write) {
 -              if (codec_drv->get_regmap)
 -                      regmap = codec_drv->get_regmap(dev);
 -              else
 -                      regmap = dev_get_regmap(dev, NULL);
 -
 -              if (regmap) {
 -                      ret = snd_soc_component_init_io(&codec->component,
 -                              regmap);
 -                      if (ret) {
 -                              dev_err(codec->dev,
 -                                              "Failed to set cache I/O:%d\n",
 -                                              ret);
 -                              goto err_cleanup;
 -                      }
 -              }
 -      }
 +#ifdef CONFIG_DEBUG_FS
 +      codec->component.init_debugfs = soc_init_codec_debugfs;
 +      codec->component.debugfs_prefix = "codec";
 +#endif
 +
 +      if (codec_drv->get_regmap)
 +              codec->component.regmap = codec_drv->get_regmap(dev);
  
        for (i = 0; i < num_dai; i++) {
                fixup_codec_formats(&dai_drv[i].playback);
diff --combined sound/soc/soc-pcm.c
@@@ -352,7 -352,7 +352,7 @@@ static void soc_pcm_apply_msb(struct sn
        } else {
                for (i = 0; i < rtd->num_codecs; i++) {
                        codec_dai = rtd->codec_dais[i];
-                       if (codec_dai->driver->playback.sig_bits == 0) {
+                       if (codec_dai->driver->capture.sig_bits == 0) {
                                bits = 0;
                                break;
                        }
@@@ -2352,11 -2352,7 +2352,11 @@@ static int dpcm_fe_dai_open(struct snd_
        mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
        fe->dpcm[stream].runtime = fe_substream->runtime;
  
 -      if (dpcm_path_get(fe, stream, &list) <= 0) {
 +      ret = dpcm_path_get(fe, stream, &list);
 +      if (ret < 0) {
 +              mutex_unlock(&fe->card->mutex);
 +              return ret;
 +      } else if (ret == 0) {
                dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
                        fe->dai_link->name, stream ? "capture" : "playback");
        }