diff options
-rw-r--r-- | sound/soc/samsung/i2s.c | 54 |
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; } |