]> Pileus Git - ~andy/linux/blobdiff - sound/soc/soc-core.c
Merge tag 'asoc-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound...
[~andy/linux] / sound / soc / soc-core.c
index 92cee24ed2dcce7eb7b7e8de3a87f09d0ffe5138..b390f00b4e9946a1b3526048de0e608035ff569f 100644 (file)
@@ -277,8 +277,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
        codec->debugfs_codec_root = debugfs_create_dir(codec->name,
                                                       debugfs_card_root);
        if (!codec->debugfs_codec_root) {
-               printk(KERN_WARNING
-                      "ASoC: Failed to create codec debugfs directory\n");
+               dev_warn(codec->dev, "Failed to create codec debugfs directory\n");
                return;
        }
 
@@ -291,8 +290,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
                                                 codec->debugfs_codec_root,
                                                 codec, &codec_reg_fops);
        if (!codec->debugfs_reg)
-               printk(KERN_WARNING
-                      "ASoC: Failed to create codec register debugfs file\n");
+               dev_warn(codec->dev, "Failed to create codec register debugfs file\n");
 
        snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
 }
@@ -302,6 +300,27 @@ 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->card->debugfs_card_root;
+
+       platform->debugfs_platform_root = debugfs_create_dir(platform->name,
+                                                      debugfs_card_root);
+       if (!platform->debugfs_platform_root) {
+               dev_warn(platform->dev,
+                       "Failed to create platform debugfs directory\n");
+               return;
+       }
+
+       snd_soc_dapm_debugfs_init(&platform->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,
                                    size_t count, loff_t *ppos)
 {
@@ -435,6 +454,14 @@ static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
 {
 }
 
+static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform)
+{
+}
+
+static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
+{
+}
+
 static inline void soc_init_card_debugfs(struct snd_soc_card *card)
 {
 }
@@ -546,18 +573,20 @@ int snd_soc_suspend(struct device *dev)
        }
 
        for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
+               struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
                if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (driver->playback.stream_name != NULL)
-                       snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
-                               SND_SOC_DAPM_STREAM_SUSPEND);
+               snd_soc_dapm_stream_event(&card->rtd[i],
+                                         SNDRV_PCM_STREAM_PLAYBACK,
+                                         codec_dai,
+                                         SND_SOC_DAPM_STREAM_SUSPEND);
 
-               if (driver->capture.stream_name != NULL)
-                       snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
-                               SND_SOC_DAPM_STREAM_SUSPEND);
+               snd_soc_dapm_stream_event(&card->rtd[i],
+                                         SNDRV_PCM_STREAM_CAPTURE,
+                                         codec_dai,
+                                         SND_SOC_DAPM_STREAM_SUSPEND);
        }
 
        /* suspend all CODECs */
@@ -660,18 +689,18 @@ static void soc_resume_deferred(struct work_struct *work)
        }
 
        for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
+               struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
 
                if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (driver->playback.stream_name != NULL)
-                       snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
-                               SND_SOC_DAPM_STREAM_RESUME);
+               snd_soc_dapm_stream_event(&card->rtd[i],
+                                         SNDRV_PCM_STREAM_PLAYBACK, codec_dai,
+                                         SND_SOC_DAPM_STREAM_RESUME);
 
-               if (driver->capture.stream_name != NULL)
-                       snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
-                               SND_SOC_DAPM_STREAM_RESUME);
+               snd_soc_dapm_stream_event(&card->rtd[i],
+                                         SNDRV_PCM_STREAM_CAPTURE, codec_dai,
+                                         SND_SOC_DAPM_STREAM_RESUME);
        }
 
        /* unmute any active DACs */
@@ -904,7 +933,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
                if (codec_dai->driver->remove) {
                        err = codec_dai->driver->remove(codec_dai);
                        if (err < 0)
-                               printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name);
+                               pr_err("asoc: failed to remove %s: %d\n",
+                                                       codec_dai->name, err);
                }
                codec_dai->probed = 0;
                list_del(&codec_dai->card_list);
@@ -916,12 +946,14 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
                if (platform->driver->remove) {
                        err = platform->driver->remove(platform);
                        if (err < 0)
-                               printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
+                               pr_err("asoc: failed to remove %s: %d\n",
+                                                       platform->name, err);
                }
 
                /* Make sure all DAPM widgets are freed */
                snd_soc_dapm_free(&platform->dapm);
 
+               soc_cleanup_platform_debugfs(platform);
                platform->probed = 0;
                list_del(&platform->card_list);
                module_put(platform->dev->driver->owner);
@@ -938,7 +970,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
                if (cpu_dai->driver->remove) {
                        err = cpu_dai->driver->remove(cpu_dai);
                        if (err < 0)
-                               printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name);
+                               pr_err("asoc: failed to remove %s: %d\n",
+                                                       cpu_dai->name, err);
                }
                cpu_dai->probed = 0;
                list_del(&cpu_dai->card_list);
@@ -980,6 +1013,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
 {
        int ret = 0;
        const struct snd_soc_codec_driver *driver = codec->driver;
+       struct snd_soc_dai *dai;
 
        codec->card = card;
        codec->dapm.card = card;
@@ -994,6 +1028,14 @@ static int soc_probe_codec(struct snd_soc_card *card,
                snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
                                          driver->num_dapm_widgets);
 
+       /* Create DAPM widgets for each DAI stream */
+       list_for_each_entry(dai, &dai_list, list) {
+               if (dai->dev != codec->dev)
+                       continue;
+
+               snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
+       }
+
        codec->dapm.idle_bias_off = driver->idle_bias_off;
 
        if (driver->probe) {
@@ -1007,7 +1049,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
        }
 
        if (driver->controls)
-               snd_soc_add_controls(codec, 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,
@@ -1039,10 +1081,14 @@ static int soc_probe_platform(struct snd_soc_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->dapm,
                        driver->dapm_widgets, driver->num_dapm_widgets);
 
+       platform->dapm.idle_bias_off = 1;
+
        if (driver->probe) {
                ret = driver->probe(platform);
                if (ret < 0) {
@@ -1068,6 +1114,7 @@ static int soc_probe_platform(struct snd_soc_card *card,
        return 0;
 
 err_probe:
+       soc_cleanup_platform_debugfs(platform);
        module_put(platform->dev->driver->owner);
 
        return ret;
@@ -1183,8 +1230,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
                if (cpu_dai->driver->probe) {
                        ret = cpu_dai->driver->probe(cpu_dai);
                        if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
-                                               cpu_dai->name);
+                               pr_err("asoc: failed to probe CPU DAI %s: %d\n",
+                                                       cpu_dai->name, ret);
                                module_put(cpu_dai->dev->driver->owner);
                                return ret;
                        }
@@ -1215,8 +1262,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
                if (codec_dai->driver->probe) {
                        ret = codec_dai->driver->probe(codec_dai);
                        if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
-                                               codec_dai->name);
+                               pr_err("asoc: failed to probe CODEC DAI %s: %d\n",
+                                                       codec_dai->name, ret);
                                return ret;
                        }
                }
@@ -1236,12 +1283,13 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
 
        ret = device_create_file(rtd->dev, &dev_attr_pmdown_time);
        if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+               pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
 
        /* create the pcm */
        ret = soc_new_pcm(rtd, num);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
+               pr_err("asoc: can't create pcm %s :%d\n",
+                               dai_link->stream_name, ret);
                return ret;
        }
 
@@ -1274,7 +1322,7 @@ static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
 
                ret = soc_ac97_dev_register(rtd->codec);
                if (ret < 0) {
-                       printk(KERN_ERR "asoc: AC97 device register failed\n");
+                       pr_err("asoc: AC97 device register failed:%d\n", ret);
                        return ret;
                }
 
@@ -1414,8 +1462,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        card->owner, 0, &card->snd_card);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create sound card for card %s\n",
-                       card->name);
+               pr_err("asoc: can't create sound card for card %s: %d\n",
+                       card->name, ret);
                mutex_unlock(&card->mutex);
                return;
        }
@@ -1468,13 +1516,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                }
        }
 
-       /* We should have a non-codec control add function but we don't */
+       snd_soc_dapm_link_dai_widgets(card);
+
        if (card->controls)
-               snd_soc_add_controls(list_first_entry(&card->codec_dev_list,
-                                                     struct snd_soc_codec,
-                                                     card_list),
-                                    card->controls,
-                                    card->num_controls);
+               snd_soc_add_card_controls(card, card->controls, card->num_controls);
 
        if (card->dapm_routes)
                snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
@@ -1488,14 +1533,14 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                if (dai_link->dai_fmt) {
                        ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
                                                  dai_link->dai_fmt);
-                       if (ret != 0)
+                       if (ret != 0 && ret != -ENOTSUPP)
                                dev_warn(card->rtd[i].codec_dai->dev,
                                         "Failed to set DAI format: %d\n",
                                         ret);
 
                        ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
                                                  dai_link->dai_fmt);
-                       if (ret != 0)
+                       if (ret != 0 && ret != -ENOTSUPP)
                                dev_warn(card->rtd[i].cpu_dai->dev,
                                         "Failed to set DAI format: %d\n",
                                         ret);
@@ -1538,7 +1583,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
 
        ret = snd_card_register(card->snd_card);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
+               pr_err("asoc: failed to register soundcard for %s: %d\n",
+                                                       card->name, ret);
                goto probe_aux_dev_err;
        }
 
@@ -1547,7 +1593,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        for (i = 0; i < card->num_rtd; i++) {
                ret = soc_register_ac97_dai_link(&card->rtd[i]);
                if (ret < 0) {
-                       printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
+                       pr_err("asoc: failed to register AC97 %s: %d\n",
+                                                       card->name, ret);
                        while (--i >= 0)
                                soc_unregister_ac97_dai_link(card->rtd[i].codec);
                        goto probe_aux_dev_err;
@@ -1600,6 +1647,10 @@ static int soc_probe(struct platform_device *pdev)
        if (!card)
                return -EINVAL;
 
+       dev_warn(&pdev->dev,
+                "ASoC machine %s should use snd_soc_register_card()\n",
+                card->name);
+
        /* Bodge while we unpick instantiation */
        card->dev = &pdev->dev;
 
@@ -1637,7 +1688,6 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card)
 
        snd_soc_dapm_free(&card->dapm);
 
-       kfree(card->rtd);
        snd_card_free(card->snd_card);
        return 0;
 
@@ -1676,7 +1726,10 @@ EXPORT_SYMBOL_GPL(snd_soc_poweroff);
 const struct dev_pm_ops snd_soc_pm_ops = {
        .suspend = snd_soc_suspend,
        .resume = snd_soc_resume,
+       .freeze = snd_soc_suspend,
+       .thaw = snd_soc_resume,
        .poweroff = snd_soc_poweroff,
+       .restore = snd_soc_resume,
 };
 EXPORT_SYMBOL_GPL(snd_soc_pm_ops);
 
@@ -1880,23 +1933,28 @@ EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw);
 int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
                                unsigned int mask, unsigned int value)
 {
-       int change;
+       bool change;
        unsigned int old, new;
        int ret;
 
-       ret = snd_soc_read(codec, reg);
-       if (ret < 0)
-               return ret;
-
-       old = ret;
-       new = (old & ~mask) | (value & mask);
-       change = old != new;
-       if (change) {
-               ret = snd_soc_write(codec, reg, new);
+       if (codec->using_regmap) {
+               ret = regmap_update_bits_check(codec->control_data, reg,
+                                              mask, value, &change);
+       } else {
+               ret = snd_soc_read(codec, reg);
                if (ret < 0)
                        return ret;
+
+               old = ret;
+               new = (old & ~mask) | (value & mask);
+               change = old != new;
+               if (change)
+                       ret = snd_soc_write(codec, reg, new);
        }
 
+       if (ret < 0)
+               return ret;
+
        return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_update_bits);
@@ -1987,7 +2045,7 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
  * Returns 0 for success, else error.
  */
 struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
-                                 void *data, char *long_name,
+                                 void *data, const char *long_name,
                                  const char *prefix)
 {
        struct snd_kcontrol_new template;
@@ -2022,9 +2080,28 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
 }
 EXPORT_SYMBOL_GPL(snd_soc_cnew);
 
+static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
+       const struct snd_kcontrol_new *controls, int num_controls,
+       const char *prefix, void *data)
+{
+       int err, i;
+
+       for (i = 0; i < num_controls; i++) {
+               const struct snd_kcontrol_new *control = &controls[i];
+               err = snd_ctl_add(card, snd_soc_cnew(control, data,
+                                                    control->name, prefix));
+               if (err < 0) {
+                       dev_err(dev, "Failed to add %s: %d\n", control->name, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
 /**
- * snd_soc_add_controls - add an array of controls to a codec.
- * Convienience function to add a list of controls. Many codecs were
+ * snd_soc_add_codec_controls - add an array of controls to a codec.
+ * Convenience function to add a list of controls. Many codecs were
  * duplicating this code.
  *
  * @codec: codec to add controls to
@@ -2033,31 +2110,19 @@ EXPORT_SYMBOL_GPL(snd_soc_cnew);
  *
  * Return 0 for success, else error.
  */
-int snd_soc_add_controls(struct snd_soc_codec *codec,
+int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
        const struct snd_kcontrol_new *controls, int num_controls)
 {
        struct snd_card *card = codec->card->snd_card;
-       int err, i;
 
-       for (i = 0; i < num_controls; i++) {
-               const struct snd_kcontrol_new *control = &controls[i];
-               err = snd_ctl_add(card, snd_soc_cnew(control, codec,
-                                                    control->name,
-                                                    codec->name_prefix));
-               if (err < 0) {
-                       dev_err(codec->dev, "%s: Failed to add %s: %d\n",
-                               codec->name, control->name, err);
-                       return err;
-               }
-       }
-
-       return 0;
+       return snd_soc_add_controls(card, codec->dev, controls, num_controls,
+                       codec->name_prefix, codec);
 }
-EXPORT_SYMBOL_GPL(snd_soc_add_controls);
+EXPORT_SYMBOL_GPL(snd_soc_add_codec_controls);
 
 /**
  * snd_soc_add_platform_controls - add an array of controls to a platform.
- * Convienience function to add a list of controls.
+ * Convenience function to add a list of controls.
  *
  * @platform: platform to add controls to
  * @controls: array of controls to add
@@ -2069,22 +2134,52 @@ int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
        const struct snd_kcontrol_new *controls, int num_controls)
 {
        struct snd_card *card = platform->card->snd_card;
-       int err, i;
-
-       for (i = 0; i < num_controls; i++) {
-               const struct snd_kcontrol_new *control = &controls[i];
-               err = snd_ctl_add(card, snd_soc_cnew(control, platform,
-                               control->name, NULL));
-               if (err < 0) {
-                       dev_err(platform->dev, "Failed to add %s %d\n",control->name, err);
-                       return err;
-               }
-       }
 
-       return 0;
+       return snd_soc_add_controls(card, platform->dev, controls, num_controls,
+                       NULL, platform);
 }
 EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
 
+/**
+ * snd_soc_add_card_controls - add an array of controls to a SoC card.
+ * Convenience function to add a list of controls.
+ *
+ * @soc_card: SoC card to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
+       const struct snd_kcontrol_new *controls, int num_controls)
+{
+       struct snd_card *card = soc_card->snd_card;
+
+       return snd_soc_add_controls(card, soc_card->dev, controls, num_controls,
+                       NULL, soc_card);
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
+
+/**
+ * snd_soc_add_dai_controls - add an array of controls to a DAI.
+ * Convienience function to add a list of controls.
+ *
+ * @dai: DAI to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
+       const struct snd_kcontrol_new *controls, int num_controls)
+{
+       struct snd_card *card = dai->card->snd_card;
+
+       return snd_soc_add_controls(card, dai->dev, controls, num_controls,
+                       NULL, dai);
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
+
 /**
  * snd_soc_info_enum_double - enumerated double mixer info callback
  * @kcontrol: mixer control
@@ -2651,6 +2746,115 @@ int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
 
+int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct soc_bytes *params = (void *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = params->num_regs * codec->val_bytes;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_info);
+
+int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int ret;
+
+       if (codec->using_regmap)
+               ret = regmap_raw_read(codec->control_data, params->base,
+                                     ucontrol->value.bytes.data,
+                                     params->num_regs * codec->val_bytes);
+       else
+               ret = -EINVAL;
+
+       /* Hide any masked bytes to ensure consistent data reporting */
+       if (ret == 0 && params->mask) {
+               switch (codec->val_bytes) {
+               case 1:
+                       ucontrol->value.bytes.data[0] &= ~params->mask;
+                       break;
+               case 2:
+                       ((u16 *)(&ucontrol->value.bytes.data))[0]
+                               &= ~params->mask;
+                       break;
+               case 4:
+                       ((u32 *)(&ucontrol->value.bytes.data))[0]
+                               &= ~params->mask;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_get);
+
+int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       int ret, len;
+       unsigned int val;
+       void *data;
+
+       if (!codec->using_regmap)
+               return -EINVAL;
+
+       data = ucontrol->value.bytes.data;
+       len = params->num_regs * codec->val_bytes;
+
+       /*
+        * If we've got a mask then we need to preserve the register
+        * bits.  We shouldn't modify the incoming data so take a
+        * copy.
+        */
+       if (params->mask) {
+               ret = regmap_read(codec->control_data, params->base, &val);
+               if (ret != 0)
+                       return ret;
+
+               val &= params->mask;
+
+               data = kmemdup(data, len, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+
+               switch (codec->val_bytes) {
+               case 1:
+                       ((u8 *)data)[0] &= ~params->mask;
+                       ((u8 *)data)[0] |= val;
+                       break;
+               case 2:
+                       ((u16 *)data)[0] &= cpu_to_be16(~params->mask);
+                       ((u16 *)data)[0] |= cpu_to_be16(val);
+                       break;
+               case 4:
+                       ((u32 *)data)[0] &= cpu_to_be32(~params->mask);
+                       ((u32 *)data)[0] |= cpu_to_be32(val);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       ret = regmap_raw_write(codec->control_data, params->base,
+                              data, len);
+
+       if (params->mask)
+               kfree(data);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
+
 /**
  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
  * @dai: DAI
@@ -2768,10 +2972,11 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-       if (dai->driver && dai->driver->ops->set_fmt)
-               return dai->driver->ops->set_fmt(dai, fmt);
-       else
+       if (dai->driver == NULL)
                return -EINVAL;
+       if (dai->driver->ops->set_fmt == NULL)
+               return -ENOTSUPP;
+       return dai->driver->ops->set_fmt(dai, fmt);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 
@@ -2875,7 +3080,8 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 */
                if (!!link->codec_name == !!link->codec_of_node) {
                        dev_err(card->dev,
-                               "Neither/both codec name/of_node are set\n");
+                               "Neither/both codec name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
 
@@ -2885,7 +3091,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 */
                if (link->platform_name && link->platform_of_node) {
                        dev_err(card->dev,
-                               "Both platform name/of_node are set\n");
+                               "Both platform name/of_node are set for %s\n", link->name);
                        return -EINVAL;
                }
 
@@ -2895,7 +3101,8 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 */
                if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) {
                        dev_err(card->dev,
-                               "Neither/both cpu_dai name/of_node are set\n");
+                               "Neither/both cpu_dai name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
        }
@@ -2906,11 +3113,13 @@ int snd_soc_register_card(struct snd_soc_card *card)
 
        soc_init_card_debugfs(card);
 
-       card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
-                           (card->num_links + card->num_aux_devs),
-                           GFP_KERNEL);
+       card->rtd = devm_kzalloc(card->dev,
+                                sizeof(struct snd_soc_pcm_runtime) *
+                                (card->num_links + card->num_aux_devs),
+                                GFP_KERNEL);
        if (card->rtd == NULL)
                return -ENOMEM;
+       card->num_rtd = 0;
        card->rtd_aux = &card->rtd[card->num_links];
 
        for (i = 0; i < card->num_links; i++)
@@ -3002,7 +3211,7 @@ static inline char *fmt_multiple_name(struct device *dev,
                struct snd_soc_dai_driver *dai_drv)
 {
        if (dai_drv->name == NULL) {
-               printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n",
+               pr_err("asoc: error - multiple DAI %s registered with no name\n",
                                dev_name(dev));
                return NULL;
        }
@@ -3177,6 +3386,7 @@ int snd_soc_register_platform(struct device *dev,
        platform->dapm.dev = dev;
        platform->dapm.platform = platform;
        platform->dapm.stream_event = platform_drv->stream_event;
+       mutex_init(&platform->mutex);
 
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
@@ -3285,6 +3495,7 @@ int snd_soc_register_codec(struct device *dev,
        codec->volatile_register = codec_drv->volatile_register;
        codec->readable_register = codec_drv->readable_register;
        codec->writable_register = codec_drv->writable_register;
+       codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
        codec->dapm.bias_level = SND_SOC_BIAS_OFF;
        codec->dapm.dev = dev;
        codec->dapm.codec = codec;
@@ -3420,10 +3631,10 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
        int i, ret;
 
        num_routes = of_property_count_strings(np, propname);
-       if (num_routes & 1) {
+       if (num_routes < 0 || num_routes & 1) {
                dev_err(card->dev,
-                       "Property '%s's length is not even\n",
-                       propname);
+                    "Property '%s' does not exist or its length is not even\n",
+                    propname);
                return -EINVAL;
        }
        num_routes /= 2;
@@ -3473,8 +3684,7 @@ 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) {
-               printk(KERN_WARNING
-                      "ASoC: Failed to create debugfs directory\n");
+               pr_warn("ASoC: Failed to create debugfs directory\n");
                snd_soc_debugfs_root = NULL;
        }