Merge remote-tracking branch 'asoc/topic/compress' into asoc-next
authorMark Brown <broonie@linaro.org>
Mon, 20 Jan 2014 11:50:41 +0000 (11:50 +0000)
committerMark Brown <broonie@linaro.org>
Mon, 20 Jan 2014 11:50:41 +0000 (11:50 +0000)
1  2 
include/sound/soc.h
sound/soc/soc-pcm.c

diff --combined include/sound/soc.h
@@@ -334,7 -334,9 +334,7 @@@ struct snd_soc_jack_pin
  #include <sound/soc-dapm.h>
  #include <sound/soc-dpcm.h>
  
 -#ifdef CONFIG_GPIOLIB
  struct snd_soc_jack_gpio;
 -#endif
  
  typedef int (*hw_write_t)(void *,const char* ,int);
  
@@@ -444,17 -446,6 +444,17 @@@ int snd_soc_jack_add_gpios(struct snd_s
                        struct snd_soc_jack_gpio *gpios);
  void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
                        struct snd_soc_jack_gpio *gpios);
 +#else
 +static inline int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
 +                                       struct snd_soc_jack_gpio *gpios)
 +{
 +      return 0;
 +}
 +
 +static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
 +                                         struct snd_soc_jack_gpio *gpios)
 +{
 +}
  #endif
  
  /* codec register bit access */
@@@ -589,6 -580,7 +589,6 @@@ struct snd_soc_jack_zone 
   *                   to provide more complex checks (eg, reading an
   *                   ADC).
   */
 -#ifdef CONFIG_GPIOLIB
  struct snd_soc_jack_gpio {
        unsigned int gpio;
        const char *name;
  
        int (*jack_status_check)(void);
  };
 -#endif
  
  struct snd_soc_jack {
        struct mutex mutex;
@@@ -886,8 -879,6 +886,8 @@@ struct snd_soc_dai_link 
  
        /* Symmetry requirements */
        unsigned int symmetric_rates:1;
 +      unsigned int symmetric_channels:1;
 +      unsigned int symmetric_samplebits:1;
  
        /* Do not create a PCM for this DAI link (Backend link) */
        unsigned int no_pcm:1;
        /* This DAI link can route to other DAI links at runtime (Frontend)*/
        unsigned int dynamic:1;
  
 +      /* DPCM capture and Playback support */
 +      unsigned int dpcm_capture:1;
 +      unsigned int dpcm_playback:1;
 +
        /* pmdown_time is ignored at stop */
        unsigned int ignore_pmdown_time:1;
  
@@@ -1042,6 -1029,7 +1042,7 @@@ struct snd_soc_pcm_runtime 
  
        /* Dynamic PCM BE runtime data */
        struct snd_soc_dpcm_runtime dpcm[2];
+       int fe_compr;
  
        long pmdown_time;
        unsigned char pop_wait:1;
diff --combined sound/soc/soc-pcm.c
@@@ -58,7 -58,7 +58,7 @@@ int snd_soc_set_runtime_hwparams(struc
  EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
  
  /* DPCM stream event, send event to FE and all active BEs. */
static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
+ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
        int event)
  {
        struct snd_soc_dpcm *dpcm;
@@@ -84,117 -84,35 +84,117 @@@ static int soc_pcm_apply_symmetry(struc
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        int ret;
  
 -      if (!soc_dai->driver->symmetric_rates &&
 -          !rtd->dai_link->symmetric_rates)
 -              return 0;
 +      if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
 +                              rtd->dai_link->symmetric_rates)) {
 +              dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
 +                              soc_dai->rate);
 +
 +              ret = snd_pcm_hw_constraint_minmax(substream->runtime,
 +                                              SNDRV_PCM_HW_PARAM_RATE,
 +                                              soc_dai->rate, soc_dai->rate);
 +              if (ret < 0) {
 +                      dev_err(soc_dai->dev,
 +                              "ASoC: Unable to apply rate constraint: %d\n",
 +                              ret);
 +                      return ret;
 +              }
 +      }
  
 -      /* This can happen if multiple streams are starting simultaneously -
 -       * the second can need to get its constraints before the first has
 -       * picked a rate.  Complain and allow the application to carry on.
 -       */
 -      if (!soc_dai->rate) {
 -              dev_warn(soc_dai->dev,
 -                       "ASoC: Not enforcing symmetric_rates due to race\n");
 -              return 0;
 +      if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
 +                              rtd->dai_link->symmetric_channels)) {
 +              dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
 +                              soc_dai->channels);
 +
 +              ret = snd_pcm_hw_constraint_minmax(substream->runtime,
 +                                              SNDRV_PCM_HW_PARAM_CHANNELS,
 +                                              soc_dai->channels,
 +                                              soc_dai->channels);
 +              if (ret < 0) {
 +                      dev_err(soc_dai->dev,
 +                              "ASoC: Unable to apply channel symmetry constraint: %d\n",
 +                              ret);
 +                      return ret;
 +              }
        }
  
 -      dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate);
 +      if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
 +                              rtd->dai_link->symmetric_samplebits)) {
 +              dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
 +                              soc_dai->sample_bits);
  
 -      ret = snd_pcm_hw_constraint_minmax(substream->runtime,
 -                                         SNDRV_PCM_HW_PARAM_RATE,
 -                                         soc_dai->rate, soc_dai->rate);
 -      if (ret < 0) {
 -              dev_err(soc_dai->dev,
 -                      "ASoC: Unable to apply rate symmetry constraint: %d\n",
 -                      ret);
 -              return ret;
 +              ret = snd_pcm_hw_constraint_minmax(substream->runtime,
 +                                              SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
 +                                              soc_dai->sample_bits,
 +                                              soc_dai->sample_bits);
 +              if (ret < 0) {
 +                      dev_err(soc_dai->dev,
 +                              "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
 +                              ret);
 +                      return ret;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
 +                              struct snd_pcm_hw_params *params)
 +{
 +      struct snd_soc_pcm_runtime *rtd = substream->private_data;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
 +      unsigned int rate, channels, sample_bits, symmetry;
 +
 +      rate = params_rate(params);
 +      channels = params_channels(params);
 +      sample_bits = snd_pcm_format_physical_width(params_format(params));
 +
 +      /* reject unmatched parameters when applying symmetry */
 +      symmetry = cpu_dai->driver->symmetric_rates ||
 +              codec_dai->driver->symmetric_rates ||
 +              rtd->dai_link->symmetric_rates;
 +      if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
 +              dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
 +                              cpu_dai->rate, rate);
 +              return -EINVAL;
 +      }
 +
 +      symmetry = cpu_dai->driver->symmetric_channels ||
 +              codec_dai->driver->symmetric_channels ||
 +              rtd->dai_link->symmetric_channels;
 +      if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
 +              dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
 +                              cpu_dai->channels, channels);
 +              return -EINVAL;
 +      }
 +
 +      symmetry = cpu_dai->driver->symmetric_samplebits ||
 +              codec_dai->driver->symmetric_samplebits ||
 +              rtd->dai_link->symmetric_samplebits;
 +      if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
 +              dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
 +                              cpu_dai->sample_bits, sample_bits);
 +              return -EINVAL;
        }
  
        return 0;
  }
  
 +static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
 +{
 +      struct snd_soc_pcm_runtime *rtd = substream->private_data;
 +      struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
 +      struct snd_soc_dai_driver *codec_driver = rtd->codec_dai->driver;
 +      struct snd_soc_dai_link *link = rtd->dai_link;
 +
 +      return cpu_driver->symmetric_rates || codec_driver->symmetric_rates ||
 +              link->symmetric_rates || cpu_driver->symmetric_channels ||
 +              codec_driver->symmetric_channels || link->symmetric_channels ||
 +              cpu_driver->symmetric_samplebits ||
 +              codec_driver->symmetric_samplebits ||
 +              link->symmetric_samplebits;
 +}
 +
  /*
   * List of sample sizes that might go over the bus for parameter
   * application.  There ought to be a wildcard sample size for things
@@@ -230,32 -148,24 +230,32 @@@ static void soc_pcm_apply_msb(struct sn
        }
  }
  
 -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,
                cpu_stream->channels_max);
 -      hw->formats = codec_stream->formats & cpu_stream->formats;
 -      hw->rates = codec_stream->rates & cpu_stream->rates;
 -      if (codec_stream->rates
 -              & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 -              hw->rates |= cpu_stream->rates;
 -      if (cpu_stream->rates
 -              & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 -              hw->rates |= codec_stream->rates;
 +      if (hw->formats)
 +              hw->formats &= codec_stream->formats & cpu_stream->formats;
 +      else
 +              hw->formats = codec_stream->formats & cpu_stream->formats;
 +      hw->rates = snd_pcm_rate_mask_intersect(codec_stream->rates,
 +              cpu_stream->rates);
 +
 +      hw->rate_min = 0;
 +      hw->rate_max = UINT_MAX;
 +
 +      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);
  }
  
  /*
@@@ -325,17 -235,15 +325,17 @@@ static int soc_pcm_open(struct snd_pcm_
  
        /* 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);
        }
  
 +      if (soc_pcm_has_symmetry(substream))
 +              runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
 +
        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);
@@@ -482,6 -390,11 +482,6 @@@ static int soc_pcm_close(struct snd_pcm
        if (!codec_dai->active)
                codec_dai->rate = 0;
  
 -      /* Muting the DAC suppresses artifacts caused during digital
 -       * shutdown, for example from stopping clocks.
 -       */
 -      snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
 -
        if (cpu_dai->driver->ops->shutdown)
                cpu_dai->driver->ops->shutdown(substream, cpu_dai);
  
@@@ -612,10 -525,6 +612,10 @@@ static int soc_pcm_hw_params(struct snd
  
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
  
 +      ret = soc_pcm_params_symmetry(substream, params);
 +      if (ret)
 +              goto out;
 +
        if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
                ret = rtd->dai_link->ops->hw_params(substream, params);
                if (ret < 0) {
                }
        }
  
 -      /* store the rate for each DAIs */
 +      /* store the parameters for each DAIs */
        cpu_dai->rate = params_rate(params);
 +      cpu_dai->channels = params_channels(params);
 +      cpu_dai->sample_bits =
 +              snd_pcm_format_physical_width(params_format(params));
 +
        codec_dai->rate = params_rate(params);
 +      codec_dai->channels = params_channels(params);
 +      codec_dai->sample_bits =
 +              snd_pcm_format_physical_width(params_format(params));
  
  out:
        mutex_unlock(&rtd->pcm_mutex);
@@@ -692,26 -594,12 +692,26 @@@ static int soc_pcm_hw_free(struct snd_p
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 -      struct snd_soc_codec *codec = rtd->codec;
 +      bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
  
 +      /* clear the corresponding DAIs parameters when going to be inactive */
 +      if (cpu_dai->active == 1) {
 +              cpu_dai->rate = 0;
 +              cpu_dai->channels = 0;
 +              cpu_dai->sample_bits = 0;
 +      }
 +
 +      if (codec_dai->active == 1) {
 +              codec_dai->rate = 0;
 +              codec_dai->channels = 0;
 +              codec_dai->sample_bits = 0;
 +      }
 +
        /* apply codec digital mute */
 -      if (!codec->active)
 +      if ((playback && codec_dai->playback_active == 1) ||
 +          (!playback && codec_dai->capture_active == 1))
                snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
  
        /* free any machine hw params */
@@@ -777,7 -665,7 +777,7 @@@ static int soc_pcm_bespoke_trigger(stru
                        return ret;
        }
  
 -      if (platform->driver->ops && platform->driver->bespoke_trigger) {
 +      if (platform->driver->bespoke_trigger) {
                ret = platform->driver->bespoke_trigger(substream, cmd);
                if (ret < 0)
                        return ret;
@@@ -885,7 -773,7 +885,7 @@@ static void dpcm_be_reparent(struct snd
  }
  
  /* disconnect a BE and FE */
static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
+ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
  {
        struct snd_soc_dpcm *dpcm, *d;
  
@@@ -981,7 -869,7 +981,7 @@@ static int widget_in_list(struct snd_so
        return 0;
  }
  
static int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
+ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
        int stream, struct snd_soc_dapm_widget_list **list_)
  {
        struct snd_soc_dai *cpu_dai = fe->cpu_dai;
        return paths;
  }
  
- static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
- {
-       kfree(*list);
- }
  static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
        struct snd_soc_dapm_widget_list **list_)
  {
@@@ -1077,7 -960,7 +1072,7 @@@ static int dpcm_add_paths(struct snd_so
                        continue;
  
                /* don't connect if FE is not running */
-               if (!fe->dpcm[stream].runtime)
+               if (!fe->dpcm[stream].runtime && !fe->fe_compr)
                        continue;
  
                /* newly connected FE and BE */
   * Find the corresponding BE DAIs that source or sink audio to this
   * FE substream.
   */
static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
+ int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
        int stream, struct snd_soc_dapm_widget_list **list, int new)
  {
        if (new)
                return dpcm_prune_paths(fe, stream, list);
  }
  
static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
+ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
  {
        struct snd_soc_dpcm *dpcm;
  
@@@ -1149,7 -1032,7 +1144,7 @@@ static void dpcm_be_dai_startup_unwind(
        }
  }
  
static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
+ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
  {
        struct snd_soc_dpcm *dpcm;
        int err, count = 0;
@@@ -1236,20 -1119,6 +1231,20 @@@ unwind
        return err;
  }
  
 +static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
 +      struct snd_soc_pcm_stream *stream)
 +{
 +      runtime->hw.rate_min = stream->rate_min;
 +      runtime->hw.rate_max = stream->rate_max;
 +      runtime->hw.channels_min = stream->channels_min;
 +      runtime->hw.channels_max = stream->channels_max;
 +      if (runtime->hw.formats)
 +              runtime->hw.formats &= stream->formats;
 +      else
 +              runtime->hw.formats = stream->formats;
 +      runtime->hw.rates = stream->rates;
 +}
 +
  static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
  {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
  
 -      if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 -              runtime->hw.rate_min = cpu_dai_drv->playback.rate_min;
 -              runtime->hw.rate_max = cpu_dai_drv->playback.rate_max;
 -              runtime->hw.channels_min = cpu_dai_drv->playback.channels_min;
 -              runtime->hw.channels_max = cpu_dai_drv->playback.channels_max;
 -              runtime->hw.formats &= cpu_dai_drv->playback.formats;
 -              runtime->hw.rates = cpu_dai_drv->playback.rates;
 -      } else {
 -              runtime->hw.rate_min = cpu_dai_drv->capture.rate_min;
 -              runtime->hw.rate_max = cpu_dai_drv->capture.rate_max;
 -              runtime->hw.channels_min = cpu_dai_drv->capture.channels_min;
 -              runtime->hw.channels_max = cpu_dai_drv->capture.channels_max;
 -              runtime->hw.formats &= cpu_dai_drv->capture.formats;
 -              runtime->hw.rates = cpu_dai_drv->capture.rates;
 -      }
 +      if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 +              dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
 +      else
 +              dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
  }
  
  static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
@@@ -1301,7 -1181,7 +1296,7 @@@ be_err
        return ret;
  }
  
static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
  {
        struct snd_soc_dpcm *dpcm;
  
@@@ -1362,7 -1242,7 +1357,7 @@@ static int dpcm_fe_dai_shutdown(struct 
        return 0;
  }
  
static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
+ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
  {
        struct snd_soc_dpcm *dpcm;
  
@@@ -1427,7 -1307,7 +1422,7 @@@ static int dpcm_fe_dai_hw_free(struct s
        return 0;
  }
  
static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
+ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
  {
        struct snd_soc_dpcm *dpcm;
        int ret;
@@@ -1557,7 -1437,7 +1552,7 @@@ static int dpcm_do_trigger(struct snd_s
        return ret;
  }
  
static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
+ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                               int cmd)
  {
        struct snd_soc_dpcm *dpcm;
@@@ -1725,7 -1605,7 +1720,7 @@@ out
        return ret;
  }
  
static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
+ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
  {
        struct snd_soc_dpcm *dpcm;
        int ret = 0;
@@@ -2141,8 -2021,10 +2136,8 @@@ int soc_new_pcm(struct snd_soc_pcm_runt
        int ret = 0, playback = 0, capture = 0;
  
        if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
 -              if (cpu_dai->driver->playback.channels_min)
 -                      playback = 1;
 -              if (cpu_dai->driver->capture.channels_min)
 -                      capture = 1;
 +              playback = rtd->dai_link->dpcm_playback;
 +              capture = rtd->dai_link->dpcm_capture;
        } else {
                if (codec_dai->driver->playback.channels_min &&
                    cpu_dai->driver->playback.channels_min)