aboutsummaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2019-02-14 17:00:11 +0100
committerMark Brown <broonie@kernel.org>2019-02-18 18:24:14 +0000
commitb5c16a24efc809554c4c651df6bd9b48b084a5a3 (patch)
tree1dc21cd80fe29d02abbee3195333377f5e83f6a5 /sound/soc
parent70605450fd42060783b0072a61a30f42a74f2917 (diff)
downloadlinux-stericsson-b5c16a24efc809554c4c651df6bd9b48b084a5a3.tar.gz
ASoC: samsung: odroid: Ensure proper sample rate on pri/sec PCM
Currently when playing sound with different sample rates actual sample rate will be determined by audio stream which starts first on either primary or secondary PCM. The audio root clock will be configured appropriately only for the first stream. As the hardware is limited to same sample rate on both interfaces we need to disallow streams with different sample rates. It is done by this patch by returning error in FE hw_params if there is already active stream running with different sample rate. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/samsung/odroid.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c
index 18bb3bfe0300..941e8c3f67a4 100644
--- a/sound/soc/samsung/odroid.c
+++ b/sound/soc/samsung/odroid.c
@@ -20,6 +20,11 @@ struct odroid_priv {
struct snd_soc_card card;
struct clk *clk_i2s_bus;
struct clk *sclk_i2s;
+
+ /* Spinlock protecting fields below */
+ spinlock_t lock;
+ unsigned int be_sample_rate;
+ bool be_active;
};
static int odroid_card_fe_startup(struct snd_pcm_substream *substream)
@@ -31,8 +36,25 @@ static int odroid_card_fe_startup(struct snd_pcm_substream *substream)
return 0;
}
+static int odroid_card_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->be_active && priv->be_sample_rate != params_rate(params))
+ ret = -EINVAL;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+}
+
static const struct snd_soc_ops odroid_card_fe_ops = {
.startup = odroid_card_fe_startup,
+ .hw_params = odroid_card_fe_hw_params,
};
static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
@@ -41,6 +63,7 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
unsigned int pll_freq, rclk_freq, rfs;
+ unsigned long flags;
int ret;
switch (params_rate(params)) {
@@ -87,11 +110,43 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->be_sample_rate = params_rate(params);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int odroid_card_be_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ priv->be_active = true;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ priv->be_active = false;
+ break;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return 0;
}
static const struct snd_soc_ops odroid_card_be_ops = {
.hw_params = odroid_card_be_hw_params,
+ .trigger = odroid_card_be_trigger,
};
static struct snd_soc_dai_link odroid_card_dais[] = {
@@ -150,6 +205,7 @@ static int odroid_audio_probe(struct platform_device *pdev)
card->owner = THIS_MODULE;
card->fully_routed = true;
+ spin_lock_init(&priv->lock);
snd_soc_card_set_drvdata(card, priv);
ret = snd_soc_of_parse_card_name(card, "model");