Commit 729b47a0 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/core' into asoc-next

parents 30010a27 e41975ed
...@@ -220,6 +220,8 @@ struct snd_soc_dai_driver { ...@@ -220,6 +220,8 @@ struct snd_soc_dai_driver {
struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream capture;
struct snd_soc_pcm_stream playback; struct snd_soc_pcm_stream playback;
unsigned int symmetric_rates:1; unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1;
/* probe ordering - for components with runtime dependencies */ /* probe ordering - for components with runtime dependencies */
int probe_order; int probe_order;
...@@ -244,6 +246,8 @@ struct snd_soc_dai { ...@@ -244,6 +246,8 @@ struct snd_soc_dai {
unsigned int capture_active:1; /* stream is in use */ unsigned int capture_active:1; /* stream is in use */
unsigned int playback_active:1; /* stream is in use */ unsigned int playback_active:1; /* stream is in use */
unsigned int symmetric_rates:1; unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
unsigned int active; unsigned int active;
unsigned char probed:1; unsigned char probed:1;
...@@ -258,6 +262,8 @@ struct snd_soc_dai { ...@@ -258,6 +262,8 @@ struct snd_soc_dai {
/* Symmetry data - only valid if symmetry is being enforced */ /* Symmetry data - only valid if symmetry is being enforced */
unsigned int rate; unsigned int rate;
unsigned int channels;
unsigned int sample_bits;
/* parent platform/codec */ /* parent platform/codec */
struct snd_soc_platform *platform; struct snd_soc_platform *platform;
......
...@@ -879,6 +879,8 @@ struct snd_soc_dai_link { ...@@ -879,6 +879,8 @@ struct snd_soc_dai_link {
/* Symmetry requirements */ /* Symmetry requirements */
unsigned int symmetric_rates:1; 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) */ /* Do not create a PCM for this DAI link (Backend link) */
unsigned int no_pcm:1; unsigned int no_pcm:1;
......
...@@ -4617,10 +4617,14 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, ...@@ -4617,10 +4617,14 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
if (id < 0 || id >= pos->num_dai) { if (id < 0 || id >= pos->num_dai) {
ret = -EINVAL; ret = -EINVAL;
} else { break;
*dai_name = pos->dai_drv[id].name;
ret = 0;
} }
ret = 0;
*dai_name = pos->dai_drv[id].name;
if (!*dai_name)
*dai_name = pos->name;
} }
break; break;
......
...@@ -99,14 +99,14 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, ...@@ -99,14 +99,14 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
config.val_bits = data_bits; config.val_bits = data_bits;
switch (control) { switch (control) {
#if defined(CONFIG_REGMAP_I2C) || defined(CONFIG_REGMAP_I2C_MODULE) #if IS_ENABLED(CONFIG_REGMAP_I2C)
case SND_SOC_I2C: case SND_SOC_I2C:
codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev), codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev),
&config); &config);
break; break;
#endif #endif
#if defined(CONFIG_REGMAP_SPI) || defined(CONFIG_REGMAP_SPI_MODULE) #if IS_ENABLED(CONFIG_REGMAP_SPI)
case SND_SOC_SPI: case SND_SOC_SPI:
codec->control_data = regmap_init_spi(to_spi_device(codec->dev), codec->control_data = regmap_init_spi(to_spi_device(codec->dev),
&config); &config);
......
...@@ -84,35 +84,117 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, ...@@ -84,35 +84,117 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret; int ret;
if (!soc_dai->driver->symmetric_rates && if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
!rtd->dai_link->symmetric_rates) rtd->dai_link->symmetric_rates)) {
return 0; dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
soc_dai->rate);
/* This can happen if multiple streams are starting simultaneously - ret = snd_pcm_hw_constraint_minmax(substream->runtime,
* the second can need to get its constraints before the first has SNDRV_PCM_HW_PARAM_RATE,
* picked a rate. Complain and allow the application to carry on. soc_dai->rate, soc_dai->rate);
*/ if (ret < 0) {
if (!soc_dai->rate) { dev_err(soc_dai->dev,
dev_warn(soc_dai->dev, "ASoC: Unable to apply rate constraint: %d\n",
"ASoC: Not enforcing symmetric_rates due to race\n"); ret);
return 0; return ret;
}
} }
dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); 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, ret = snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_CHANNELS,
soc_dai->rate, soc_dai->rate); 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;
}
}
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_SAMPLE_BITS,
soc_dai->sample_bits,
soc_dai->sample_bits);
if (ret < 0) { if (ret < 0) {
dev_err(soc_dai->dev, dev_err(soc_dai->dev,
"ASoC: Unable to apply rate symmetry constraint: %d\n", "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
ret); ret);
return ret; return ret;
} }
}
return 0; 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 * List of sample sizes that might go over the bus for parameter
* application. There ought to be a wildcard sample size for things * application. There ought to be a wildcard sample size for things
...@@ -249,6 +331,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ...@@ -249,6 +331,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
&cpu_dai_drv->capture); &cpu_dai_drv->capture);
} }
if (soc_pcm_has_symmetry(substream))
runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
ret = -EINVAL; ret = -EINVAL;
if (!runtime->hw.rates) { if (!runtime->hw.rates) {
printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
...@@ -396,11 +481,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) ...@@ -396,11 +481,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
if (!codec_dai->active) if (!codec_dai->active)
codec_dai->rate = 0; 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) if (cpu_dai->driver->ops->shutdown)
cpu_dai->driver->ops->shutdown(substream, cpu_dai); cpu_dai->driver->ops->shutdown(substream, cpu_dai);
...@@ -531,6 +611,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -531,6 +611,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 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) { if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
ret = rtd->dai_link->ops->hw_params(substream, params); ret = rtd->dai_link->ops->hw_params(substream, params);
if (ret < 0) { if (ret < 0) {
...@@ -567,9 +651,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -567,9 +651,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
} }
} }
/* store the rate for each DAIs */ /* store the parameters for each DAIs */
cpu_dai->rate = params_rate(params); 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->rate = params_rate(params);
codec_dai->channels = params_channels(params);
codec_dai->sample_bits =
snd_pcm_format_physical_width(params_format(params));
out: out:
mutex_unlock(&rtd->pcm_mutex); mutex_unlock(&rtd->pcm_mutex);
...@@ -604,6 +695,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) ...@@ -604,6 +695,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 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 */ /* apply codec digital mute */
if ((playback && codec_dai->playback_active == 1) || if ((playback && codec_dai->playback_active == 1) ||
(!playback && codec_dai->capture_active == 1)) (!playback && codec_dai->capture_active == 1))
......
...@@ -59,10 +59,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) ...@@ -59,10 +59,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
static const struct snd_pcm_hardware dummy_dma_hardware = { static const struct snd_pcm_hardware dummy_dma_hardware = {
.formats = 0xffffffff,
.channels_min = 1,
.channels_max = UINT_MAX,
/* Random values to keep userspace happy when checking constraints */ /* Random values to keep userspace happy when checking constraints */
.info = SNDRV_PCM_INFO_INTERLEAVED | .info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER, SNDRV_PCM_INFO_BLOCK_TRANSFER,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment