Merge tag 'dt-fixes-for-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/robh...
[firefly-linux-kernel-4.4.55.git] / sound / soc / soc-pcm.c
index 591f0f3074c58b75eeb5b99a939bc9bf46ffae52..11a90cd027faca2956172f3dfa92f6d2ee46a8fe 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
@@ -147,12 +148,12 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
        }
 }
 
-static void soc_pcm_init_runtime_hw(struct snd_pcm_hardware *hw,
+static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
        struct snd_soc_pcm_stream *codec_stream,
        struct snd_soc_pcm_stream *cpu_stream)
 {
-       hw->rate_min = max(codec_stream->rate_min, cpu_stream->rate_min);
-       hw->rate_max = max(codec_stream->rate_max, cpu_stream->rate_max);
+       struct snd_pcm_hardware *hw = &runtime->hw;
+
        hw->channels_min = max(codec_stream->channels_min,
                cpu_stream->channels_min);
        hw->channels_max = min(codec_stream->channels_max,
@@ -165,6 +166,13 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_hardware *hw,
        if (cpu_stream->rates
                & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
                hw->rates |= codec_stream->rates;
+
+       snd_pcm_limit_hw_rates(runtime);
+
+       hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
+       hw->rate_min = max(hw->rate_min, codec_stream->rate_min);
+       hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
+       hw->rate_max = min_not_zero(hw->rate_max, codec_stream->rate_max);
 }
 
 /*
@@ -183,6 +191,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
        int ret = 0;
 
+       pinctrl_pm_select_default_state(cpu_dai->dev);
+       pinctrl_pm_select_default_state(codec_dai->dev);
        pm_runtime_get_sync(cpu_dai->dev);
        pm_runtime_get_sync(codec_dai->dev);
        pm_runtime_get_sync(platform->dev);
@@ -232,15 +242,14 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 
        /* Check that the codec and cpu DAIs are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->playback,
+               soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback,
                        &cpu_dai_drv->playback);
        } else {
-               soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->capture,
+               soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture,
                        &cpu_dai_drv->capture);
        }
 
        ret = -EINVAL;
-       snd_pcm_limit_hw_rates(runtime);
        if (!runtime->hw.rates) {
                printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
                        codec_dai->name, cpu_dai->name);
@@ -317,6 +326,10 @@ out:
        pm_runtime_put(platform->dev);
        pm_runtime_put(codec_dai->dev);
        pm_runtime_put(cpu_dai->dev);
+       if (!codec_dai->active)
+               pinctrl_pm_select_sleep_state(codec_dai->dev);
+       if (!cpu_dai->active)
+               pinctrl_pm_select_sleep_state(cpu_dai->dev);
 
        return ret;
 }
@@ -426,6 +439,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        pm_runtime_put(platform->dev);
        pm_runtime_put(codec_dai->dev);
        pm_runtime_put(cpu_dai->dev);
+       if (!codec_dai->active)
+               pinctrl_pm_select_sleep_state(codec_dai->dev);
+       if (!cpu_dai->active)
+               pinctrl_pm_select_sleep_state(cpu_dai->dev);
 
        return 0;
 }