ASoC: wm9712: Remove driver specific version
[deliverable/linux.git] / sound / soc / soc-pcm.c
index ee15337353fae5f2cf16f5ab86f94d13440dc6bd..93be95b7864c7be2ea9936c8c67020f582a02613 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
@@ -61,6 +62,41 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
        return 0;
 }
 
+/*
+ * List of sample sizes that might go over the bus for parameter
+ * application.  There ought to be a wildcard sample size for things
+ * like the DAC/ADC resolution to use but there isn't right now.
+ */
+static int sample_sizes[] = {
+       24, 32,
+};
+
+static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       int ret, i, bits;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               bits = dai->driver->playback.sig_bits;
+       else
+               bits = dai->driver->capture.sig_bits;
+
+       if (!bits)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) {
+               if (bits >= sample_sizes[i])
+                       continue;
+
+               ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0,
+                                                  sample_sizes[i], bits);
+               if (ret != 0)
+                       dev_warn(dai->dev,
+                                "Failed to set MSB %d/%d: %d\n",
+                                bits, sample_sizes[i], ret);
+       }
+}
+
 /*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
@@ -77,6 +113,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
        int ret = 0;
 
+       pm_runtime_get_sync(cpu_dai->dev);
+       pm_runtime_get_sync(codec_dai->dev);
+       pm_runtime_get_sync(platform->dev);
+
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
        /* startup the audio subsystem */
@@ -182,6 +222,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                goto config_err;
        }
 
+       soc_pcm_apply_msb(substream, codec_dai);
+       soc_pcm_apply_msb(substream, cpu_dai);
+
        /* Symmetry only applies if we've already got an active stream. */
        if (cpu_dai->active) {
                ret = soc_pcm_apply_symmetry(substream, cpu_dai);
@@ -233,6 +276,11 @@ platform_err:
                cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 out:
        mutex_unlock(&rtd->pcm_mutex);
+
+       pm_runtime_put(platform->dev);
+       pm_runtime_put(codec_dai->dev);
+       pm_runtime_put(cpu_dai->dev);
+
        return ret;
 }
 
@@ -319,7 +367,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        cpu_dai->runtime = NULL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (unlikely(codec->ignore_pmdown_time)) {
+               if (codec->ignore_pmdown_time ||
+                   rtd->dai_link->ignore_pmdown_time) {
                        /* powered down playback stream now */
                        snd_soc_dapm_stream_event(rtd,
                                codec_dai->driver->playback.stream_name,
@@ -338,6 +387,11 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        }
 
        mutex_unlock(&rtd->pcm_mutex);
+
+       pm_runtime_put(platform->dev);
+       pm_runtime_put(codec_dai->dev);
+       pm_runtime_put(cpu_dai->dev);
+
        return 0;
 }
 
@@ -582,17 +636,6 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
        return offset;
 }
 
-/* ASoC PCM operations */
-static struct snd_pcm_ops soc_pcm_ops = {
-       .open           = soc_pcm_open,
-       .close          = soc_pcm_close,
-       .hw_params      = soc_pcm_hw_params,
-       .hw_free        = soc_pcm_hw_free,
-       .prepare        = soc_pcm_prepare,
-       .trigger        = soc_pcm_trigger,
-       .pointer        = soc_pcm_pointer,
-};
-
 /* create a new pcm */
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 {
@@ -600,10 +643,19 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_pcm_ops *soc_pcm_ops = &rtd->ops;
        struct snd_pcm *pcm;
        char new_name[64];
        int ret = 0, playback = 0, capture = 0;
 
+       soc_pcm_ops->open       = soc_pcm_open;
+       soc_pcm_ops->close      = soc_pcm_close;
+       soc_pcm_ops->hw_params  = soc_pcm_hw_params;
+       soc_pcm_ops->hw_free    = soc_pcm_hw_free;
+       soc_pcm_ops->prepare    = soc_pcm_prepare;
+       soc_pcm_ops->trigger    = soc_pcm_trigger;
+       soc_pcm_ops->pointer    = soc_pcm_pointer;
+
        /* check client and interface hw capabilities */
        snprintf(new_name, sizeof(new_name), "%s %s-%d",
                        rtd->dai_link->stream_name, codec_dai->name, num);
@@ -627,20 +679,20 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        rtd->pcm = pcm;
        pcm->private_data = rtd;
        if (platform->driver->ops) {
-               soc_pcm_ops.mmap = platform->driver->ops->mmap;
-               soc_pcm_ops.pointer = platform->driver->ops->pointer;
-               soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
-               soc_pcm_ops.copy = platform->driver->ops->copy;
-               soc_pcm_ops.silence = platform->driver->ops->silence;
-               soc_pcm_ops.ack = platform->driver->ops->ack;
-               soc_pcm_ops.page = platform->driver->ops->page;
+               soc_pcm_ops->mmap = platform->driver->ops->mmap;
+               soc_pcm_ops->pointer = platform->driver->ops->pointer;
+               soc_pcm_ops->ioctl = platform->driver->ops->ioctl;
+               soc_pcm_ops->copy = platform->driver->ops->copy;
+               soc_pcm_ops->silence = platform->driver->ops->silence;
+               soc_pcm_ops->ack = platform->driver->ops->ack;
+               soc_pcm_ops->page = platform->driver->ops->page;
        }
 
        if (playback)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);
 
        if (capture)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);
 
        if (platform->driver->pcm_new) {
                ret = platform->driver->pcm_new(rtd);
This page took 0.031268 seconds and 5 git commands to generate.