summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dai.h1
-rw-r--r--include/sound/soc.h22
-rw-r--r--sound/soc/codecs/adav80x.c4
-rw-r--r--sound/soc/codecs/tlv320aic23.c2
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/uda1380.c2
-rw-r--r--sound/soc/codecs/wl1273.c2
-rw-r--r--sound/soc/codecs/wm8711.c2
-rw-r--r--sound/soc/codecs/wm8753.c4
-rw-r--r--sound/soc/soc-compress.c65
-rw-r--r--sound/soc/soc-core.c22
-rw-r--r--sound/soc/soc-pcm.c109
12 files changed, 143 insertions, 94 deletions
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 71f27c4..8763e53 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -270,6 +270,7 @@ struct snd_soc_dai {
/* parent platform/codec */
struct snd_soc_platform *platform;
struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
struct snd_soc_card *card;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 08cb677..5710f9e 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -427,6 +427,10 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
const char *dai_link);
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
+
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -666,6 +670,11 @@ struct snd_soc_component {
const char *name;
int id;
struct device *dev;
+
+ unsigned int active;
+
+ unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
+
struct list_head list;
struct snd_soc_dai_driver *dai_drv;
@@ -693,7 +702,6 @@ struct snd_soc_codec {
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
- unsigned int active;
unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
unsigned int probed:1; /* Codec has been probed */
@@ -719,7 +727,6 @@ struct snd_soc_codec {
/* dapm */
struct snd_soc_dapm_context dapm;
- unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
@@ -1202,6 +1209,17 @@ static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e,
return e->values[item];
}
+static inline bool snd_soc_component_is_active(
+ struct snd_soc_component *component)
+{
+ return component->active != 0;
+}
+
+static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec)
+{
+ return snd_soc_component_is_active(&codec->component);
+}
+
int snd_soc_util_init(void);
void snd_soc_util_exit(void);
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index ab790d5..f0f18ea 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -727,7 +727,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- if (!codec->active || !adav80x->rate)
+ if (!snd_soc_codec_is_active(codec) || !adav80x->rate)
return 0;
return snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -740,7 +740,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- if (!codec->active)
+ if (!snd_soc_codec_is_active(codec))
adav80x->rate = 0;
}
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 5d430cc..458a6ae 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -400,7 +400,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
- if (!codec->active) {
+ if (!snd_soc_codec_is_active(codec)) {
udelay(50);
snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
}
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 4f35839..35b2d24 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -461,7 +461,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
if (dac33->fifo_mode == ucontrol->value.integer.value[0])
return 0;
/* Do not allow changes while stream is running*/
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EPERM;
if (ucontrol->value.integer.value[0] < 0 ||
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 726df6d..8e3940d 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
/* the interpolator & decimator regs must only be written when the
* codec DAI is active.
*/
- if (!codec->active && (reg >= UDA1380_MVOL))
+ if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL))
return 0;
pr_debug("uda1380: hw write %x val %x\n", reg, value);
if (codec->hw_write(codec->control_data, data, 3) == 3) {
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index b7ab2ef..47e96ff 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
return 0;
/* Do not allow changes while stream is running */
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EPERM;
if (ucontrol->value.integer.value[0] < 0 ||
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index d99f948..6efcc40 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
/* deactivate */
- if (!codec->active) {
+ if (!snd_soc_codec_is_active(codec)) {
udelay(50);
snd_soc_write(codec, WM8711_ACTIVE, 0x0);
}
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index be85da9..5cf4beb 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
if (wm8753->dai_func == ucontrol->value.integer.value[0])
return 0;
- if (codec->active)
+ if (snd_soc_codec_is_active(codec))
return -EBUSY;
ioctl = snd_soc_read(codec, WM8753_IOCTL);
@@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
/* the digital mute covers the HiFi and Voice DAC's on the WM8753.
* make sure we check if they are not both active when we mute */
if (mute && wm8753->dai_func == 1) {
- if (!codec->active)
+ if (!snd_soc_codec_is_active(codec))
snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
} else {
if (mute)
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 5e9690c..91083e6 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
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;
int ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
}
}
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
-
- cpu_dai->active++;
- codec_dai->active++;
- rtd->codec->active++;
+ snd_soc_runtime_activate(rtd, cstream->direction);
mutex_unlock(&rtd->pcm_mutex);
@@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
struct snd_soc_platform *platform = fe->platform;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- struct snd_soc_dai *codec_dai = fe->codec_dai;
struct snd_soc_dpcm *dpcm;
struct snd_soc_dapm_widget_list *list;
int stream;
@@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
-
- cpu_dai->active++;
- codec_dai->active++;
- fe->codec->active++;
+ snd_soc_runtime_activate(fe, stream);
mutex_unlock(&fe->card->mutex);
@@ -202,23 +178,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
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;
+ int stream;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ else
+ stream = SNDRV_PCM_STREAM_CAPTURE;
- snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
+ snd_soc_runtime_deactivate(rtd, stream);
- cpu_dai->active--;
- codec_dai->active--;
- codec->active--;
+ snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
if (!cpu_dai->active)
cpu_dai->rate = 0;
@@ -235,8 +206,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
cpu_dai->runtime = NULL;
if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
- rtd->dai_link->ignore_pmdown_time) {
+ if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
SND_SOC_DAPM_STREAM_STOP);
@@ -261,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *fe = cstream->private_data;
struct snd_soc_platform *platform = fe->platform;
- struct snd_soc_dai *cpu_dai = fe->cpu_dai;
- struct snd_soc_dai *codec_dai = fe->codec_dai;
struct snd_soc_dpcm *dpcm;
int stream, ret;
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
stream = SNDRV_PCM_STREAM_PLAYBACK;
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
+ else
stream = SNDRV_PCM_STREAM_CAPTURE;
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
- cpu_dai->active--;
- codec_dai->active--;
- fe->codec->active--;
+ snd_soc_runtime_deactivate(fe, stream);
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2ddc7a4..1fa7dda 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3869,11 +3869,13 @@ static inline char *fmt_multiple_name(struct device *dev,
/**
* snd_soc_register_dai - Register a DAI with the ASoC core
*
- * @dai: DAI to register
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAIs
*/
-static int snd_soc_register_dai(struct device *dev,
+static int snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv)
{
+ struct device *dev = component->dev;
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
@@ -3890,6 +3892,7 @@ static int snd_soc_register_dai(struct device *dev,
return -ENOMEM;
}
+ dai->component = component;
dai->dev = dev;
dai->driver = dai_drv;
dai->dapm.dev = dev;
@@ -3947,12 +3950,14 @@ found:
/**
* snd_soc_register_dais - Register multiple DAIs with the ASoC core
*
- * @dai: Array of DAIs to register
+ * @component: The component the DAIs are registered for
+ * @dai_drv: DAI driver to use for the DAIs
* @count: Number of DAIs
*/
-static int snd_soc_register_dais(struct device *dev,
+static int snd_soc_register_dais(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv, size_t count)
{
+ struct device *dev = component->dev;
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
int i, ret = 0;
@@ -3975,6 +3980,7 @@ static int snd_soc_register_dais(struct device *dev,
goto err;
}
+ dai->component = component;
dai->dev = dev;
dai->driver = &dai_drv[i];
if (dai->driver->id)
@@ -4071,9 +4077,9 @@ __snd_soc_register_component(struct device *dev,
* since it had been used snd_soc_register_dais(),
*/
if ((1 == num_dai) && allow_single_dai)
- ret = snd_soc_register_dai(dev, dai_drv);
+ ret = snd_soc_register_dai(cmpnt, dai_drv);
else
- ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+ ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai);
if (ret < 0) {
dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
goto error_component_name;
@@ -4106,6 +4112,8 @@ int snd_soc_register_component(struct device *dev,
return -ENOMEM;
}
+ cmpnt->ignore_pmdown_time = true;
+
return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
dai_drv, num_dai, true);
}
@@ -4304,7 +4312,7 @@ int snd_soc_register_codec(struct device *dev,
codec->volatile_register = codec_drv->volatile_register;
codec->readable_register = codec_drv->readable_register;
codec->writable_register = codec_drv->writable_register;
- codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;
+ codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.dev = dev;
codec->dapm.codec = codec;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 47e1ce7..2cedf09 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -35,6 +35,86 @@
#define DPCM_MAX_BE_USERS 8
/**
+ * snd_soc_runtime_activate() - Increment active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is activated
+ * @stream: Direction of the PCM stream
+ *
+ * Increments the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is opened.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ lockdep_assert_held(&rtd->pcm_mutex);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->playback_active++;
+ codec_dai->playback_active++;
+ } else {
+ cpu_dai->capture_active++;
+ codec_dai->capture_active++;
+ }
+
+ cpu_dai->active++;
+ codec_dai->active++;
+ cpu_dai->component->active++;
+ codec_dai->component->active++;
+}
+
+/**
+ * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components
+ * @rtd: ASoC PCM runtime that is deactivated
+ * @stream: Direction of the PCM stream
+ *
+ * Decrements the active count for all the DAIs and components attached to a PCM
+ * runtime. Should typically be called when a stream is closed.
+ *
+ * Must be called with the rtd->pcm_mutex being held
+ */
+void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ lockdep_assert_held(&rtd->pcm_mutex);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cpu_dai->playback_active--;
+ codec_dai->playback_active--;
+ } else {
+ cpu_dai->capture_active--;
+ codec_dai->capture_active--;
+ }
+
+ cpu_dai->active--;
+ codec_dai->active--;
+ cpu_dai->component->active--;
+ codec_dai->component->active--;
+}
+
+/**
+ * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
+ * @rtd: The ASoC PCM runtime that should be checked.
+ *
+ * This function checks whether the power down delay should be ignored for a
+ * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
+ * been configured to ignore the delay, or if none of the components benefits
+ * from having the delay.
+ */
+bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
+{
+ if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
+ return true;
+
+ return rtd->cpu_dai->component->ignore_pmdown_time &&
+ rtd->codec_dai->component->ignore_pmdown_time;
+}
+
+/**
* snd_soc_set_runtime_hwparams - set the runtime hardware parameters
* @substream: the pcm substream
* @hw: the hardware parameters
@@ -378,16 +458,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.rate_max);
dynamic:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback_active++;
- codec_dai->playback_active++;
- } else {
- cpu_dai->capture_active++;
- codec_dai->capture_active++;
- }
- cpu_dai->active++;
- codec_dai->active++;
- rtd->codec->active++;
+
+ snd_soc_runtime_activate(rtd, substream->stream);
+
mutex_unlock(&rtd->pcm_mutex);
return 0;
@@ -459,21 +532,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
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;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- cpu_dai->playback_active--;
- codec_dai->playback_active--;
- } else {
- cpu_dai->capture_active--;
- codec_dai->capture_active--;
- }
-
- cpu_dai->active--;
- codec_dai->active--;
- codec->active--;
+ snd_soc_runtime_deactivate(rtd, substream->stream);
/* clear the corresponding DAIs rate when inactive */
if (!cpu_dai->active)
@@ -496,8 +558,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
cpu_dai->runtime = NULL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
- rtd->dai_link->ignore_pmdown_time) {
+ if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
/* powered down playback stream now */
snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
OpenPOWER on IntegriCloud