summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/samsung/i2s.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 10b19a4afe86..8d8965e7107c 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -477,6 +477,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
u32 mod, mask, val = 0;
unsigned long flags;
+ int ret = 0;
+
+ pm_runtime_get_sync(dai->dev);
spin_lock_irqsave(i2s->lock, flags);
mod = readl(i2s->addr + I2SMOD);
@@ -501,7 +504,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
&& (mod & cdcon_mask))))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto err;
}
if (dir == SND_SOC_CLOCK_IN)
@@ -529,7 +533,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
} else {
i2s->rclk_srcrate =
clk_get_rate(i2s->op_clk);
- return 0;
+ goto done;
}
}
@@ -540,8 +544,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
i2s->op_clk = clk_get(&i2s->pdev->dev,
"i2s_opclk0");
- if (WARN_ON(IS_ERR(i2s->op_clk)))
- return PTR_ERR(i2s->op_clk);
+ if (WARN_ON(IS_ERR(i2s->op_clk))) {
+ ret = PTR_ERR(i2s->op_clk);
+ goto err;
+ }
clk_prepare_enable(i2s->op_clk);
i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
@@ -555,12 +561,13 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
|| (clk_id && !(mod & rsrc_mask))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto err;
} else {
/* Call can't be on the active DAI */
i2s->op_clk = other->op_clk;
i2s->rclk_srcrate = other->rclk_srcrate;
- return 0;
+ goto done;
}
if (clk_id == 1)
@@ -568,7 +575,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
break;
default:
dev_err(&i2s->pdev->dev, "We don't serve that!\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
spin_lock_irqsave(i2s->lock, flags);
@@ -576,8 +584,13 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
mod = (mod & ~mask) | val;
writel(mod, i2s->addr + I2SMOD);
spin_unlock_irqrestore(i2s->lock, flags);
+done:
+ pm_runtime_put(dai->dev);
return 0;
+err:
+ pm_runtime_put(dai->dev);
+ return ret;
}
static int i2s_set_fmt(struct snd_soc_dai *dai,
@@ -646,6 +659,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL;
}
+ pm_runtime_get_sync(dai->dev);
spin_lock_irqsave(i2s->lock, flags);
mod = readl(i2s->addr + I2SMOD);
/*
@@ -655,6 +669,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
if (any_active(i2s) &&
((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
spin_unlock_irqrestore(i2s->lock, flags);
+ pm_runtime_put(dai->dev);
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
@@ -664,6 +679,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
mod |= tmp;
writel(mod, i2s->addr + I2SMOD);
spin_unlock_irqrestore(i2s->lock, flags);
+ pm_runtime_put(dai->dev);
return 0;
}
@@ -675,6 +691,8 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
u32 mod, mask = 0, val = 0;
unsigned long flags;
+ WARN_ON(!pm_runtime_active(dai->dev));
+
if (!is_secondary(i2s))
mask |= (MOD_DC2_EN | MOD_DC1_EN);
@@ -763,6 +781,8 @@ static int i2s_startup(struct snd_pcm_substream *substream,
struct i2s_dai *other = get_other_dai(i2s);
unsigned long flags;
+ pm_runtime_get_sync(dai->dev);
+
spin_lock_irqsave(&lock, flags);
i2s->mode |= DAI_OPENED;
@@ -800,6 +820,8 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
i2s->bfs = 0;
spin_unlock_irqrestore(&lock, flags);
+
+ pm_runtime_put(dai->dev);
}
static int config_setup(struct i2s_dai *i2s)
@@ -874,6 +896,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pm_runtime_get_sync(dai->dev);
spin_lock_irqsave(i2s->lock, flags);
if (config_setup(i2s)) {
@@ -902,6 +925,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
}
spin_unlock_irqrestore(i2s->lock, flags);
+ pm_runtime_put(dai->dev);
break;
}
@@ -916,13 +940,16 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai,
switch (div_id) {
case SAMSUNG_I2S_DIV_BCLK:
+ pm_runtime_get_sync(dai->dev);
if ((any_active(i2s) && div && (get_bfs(i2s) != div))
|| (other && other->bfs && (other->bfs != div))) {
+ pm_runtime_put(dai->dev);
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
}
i2s->bfs = div;
+ pm_runtime_put(dai->dev);
break;
default:
dev_err(&i2s->pdev->dev,
@@ -941,6 +968,8 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
snd_pcm_sframes_t delay;
const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
+ WARN_ON(!pm_runtime_active(dai->dev));
+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
delay = FIC_RXCOUNT(reg);
else if (is_secondary(i2s))
@@ -984,6 +1013,8 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
struct i2s_dai *other = get_other_dai(i2s);
unsigned long flags;
+ pm_runtime_get_sync(dai->dev);
+
if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */
snd_soc_dai_init_dma_data(dai, &other->sec_dai->dma_playback,
NULL);
@@ -1016,6 +1047,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
if (!is_opened(other))
i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
0, SND_SOC_CLOCK_IN);
+ pm_runtime_put(dai->dev);
return 0;
}
@@ -1025,6 +1057,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
unsigned long flags;
+ pm_runtime_get_sync(dai->dev);
+
if (!is_secondary(i2s)) {
if (i2s->quirks & QUIRK_NEED_RSTCLR) {
spin_lock_irqsave(i2s->lock, flags);
@@ -1033,6 +1067,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
}
}
+ pm_runtime_put(dai->dev);
+
return 0;
}
@@ -1322,7 +1358,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, pri_dai);
-
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = i2s_register_clock_provider(pdev);
@@ -1345,10 +1381,12 @@ static int samsung_i2s_remove(struct platform_device *pdev)
pri_dai->sec_dai = NULL;
sec_dai->pri_dai = NULL;
+ pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
i2s_unregister_clock_provider(pdev);
clk_disable_unprepare(pri_dai->clk);
+ pm_runtime_put_noidle(&pdev->dev);
return 0;
}