Merge branch 'drm-ttm-unmappable' into drm-core-next
[pandora-kernel.git] / sound / soc / soc-core.c
index 0a6440c..ad7f952 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <sound/ac97_codec.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -130,6 +131,29 @@ static ssize_t codec_reg_show(struct device *dev,
 
 static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
 
+static ssize_t pmdown_time_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct snd_soc_device *socdev = dev_get_drvdata(dev);
+       struct snd_soc_card *card = socdev->card;
+
+       return sprintf(buf, "%ld\n", card->pmdown_time);
+}
+
+static ssize_t pmdown_time_set(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct snd_soc_device *socdev = dev_get_drvdata(dev);
+       struct snd_soc_card *card = socdev->card;
+
+       strict_strtol(buf, 10, &card->pmdown_time);
+
+       return count;
+}
+
+static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
+
 #ifdef CONFIG_DEBUG_FS
 static int codec_reg_open_file(struct inode *inode, struct file *file)
 {
@@ -404,24 +428,24 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        if (!runtime->hw.rates) {
                printk(KERN_ERR "asoc: %s <-> %s No matching rates\n",
                        codec_dai->name, cpu_dai->name);
-               goto machine_err;
+               goto config_err;
        }
        if (!runtime->hw.formats) {
                printk(KERN_ERR "asoc: %s <-> %s No matching formats\n",
                        codec_dai->name, cpu_dai->name);
-               goto machine_err;
+               goto config_err;
        }
        if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
                printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
                        codec_dai->name, cpu_dai->name);
-               goto machine_err;
+               goto config_err;
        }
 
        /* Symmetry only applies if we've already got an active stream. */
        if (cpu_dai->active || codec_dai->active) {
                ret = soc_pcm_apply_symmetry(substream);
                if (ret != 0)
-                       goto machine_err;
+                       goto config_err;
        }
 
        pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
@@ -441,10 +465,14 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        mutex_unlock(&pcm_mutex);
        return 0;
 
-machine_err:
+config_err:
        if (machine->ops && machine->ops->shutdown)
                machine->ops->shutdown(substream);
 
+machine_err:
+       if (codec_dai->ops->shutdown)
+               codec_dai->ops->shutdown(substream, codec_dai);
+
 codec_dai_err:
        if (platform->pcm_ops->close)
                platform->pcm_ops->close(substream);
@@ -542,7 +570,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
                /* start delayed pop wq here for playback streams */
                codec_dai->pop_wait = 1;
                schedule_delayed_work(&card->delayed_work,
-                       msecs_to_jiffies(pmdown_time));
+                       msecs_to_jiffies(card->pmdown_time));
        } else {
                /* capture streams can be powered down now */
                snd_soc_dapm_stream_event(codec,
@@ -940,6 +968,12 @@ static int soc_resume(struct device *dev)
        struct snd_soc_card *card = socdev->card;
        struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
 
+       /* If the initialization of this soc device failed, there is no codec
+        * associated with it. Just bail out in this case.
+        */
+       if (!card->codec)
+               return 0;
+
        /* AC97 devices might have other drivers hanging off them so
         * need to resume immediately.  Other drivers don't have that
         * problem and may take a substantial amount of time to resume
@@ -1039,6 +1073,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        dev_dbg(card->dev, "All components present, instantiating\n");
 
        /* Found everything, bring it up */
+       card->pmdown_time = pmdown_time;
+
        if (card->probe) {
                ret = card->probe(pdev);
                if (ret < 0)
@@ -1122,6 +1158,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        if (ret < 0)
                printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
 
+       ret = device_create_file(card->socdev->dev, &dev_attr_pmdown_time);
+       if (ret < 0)
+               printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+
        ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
        if (ret < 0)
                printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
@@ -1276,8 +1316,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
        codec_dai->codec = card->codec;
 
        /* check client and interface hw capabilities */
-       sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name,
-               num);
+       snprintf(new_name, sizeof(new_name), "%s %s-%d",
+                dai_link->stream_name, codec_dai->name, num);
 
        if (codec_dai->playback.channels_min)
                playback = 1;
@@ -1368,6 +1408,7 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 
        codec->ac97->bus->ops = ops;
        codec->ac97->num = num;
+       codec->dev = &codec->ac97->dev;
        mutex_unlock(&codec->mutex);
        return 0;
 }
@@ -1427,9 +1468,9 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits);
  *
  * Returns 1 for change else 0.
  */
-static int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
-                               unsigned short reg, unsigned int mask,
-                               unsigned int value)
+int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
+                              unsigned short reg, unsigned int mask,
+                              unsigned int value)
 {
        int change;
 
@@ -1439,6 +1480,7 @@ static int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
 
        return change;
 }
+EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
 
 /**
  * snd_soc_test_bits - test register for change
@@ -1507,7 +1549,8 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
                        mutex_unlock(&codec->mutex);
                        return ret;
                }
-               if (card->dai_link[i].codec_dai->ac97_control) {
+               /* Check for codec->ac97 to handle the ac97.c fun */
+               if (card->dai_link[i].codec_dai->ac97_control && codec->ac97) {
                        snd_ac97_dev_add_pdata(codec->ac97,
                                card->dai_link[i].cpu_dai->ac97_pdata);
                }