summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorNicolin Chen <Guangyu.Chen@freescale.com>2014-01-06 16:43:19 +0800
committerNicolin Chen <Guangyu.Chen@freescale.com>2014-01-16 19:27:48 +0800
commit51eb47421c36dbb4d7542cd79f6f2e63e9e0df4a (patch)
tree1240377f7b05b8aebbc01e42fe4a8e1bc78b2df2 /sound
parent8e8c6b5c1386f24af7c993916e86f58065ac3036 (diff)
ENGR00295423-2 ASoC: fsl_ssi: Don't set clock rate in hw_params()
Leaving clk_set_rate() in hw_params() is a bit dangerous when handling two substreams. So we let set_sysclk() finish the clk_set_rate() directly. This patch also adds spinlock to protect the baud clock configuration so that it won't be broken during race. Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com> (cherry picked from commit d3818ba35e4cbb6a3fa769eb83ceb7335b7c19e6)
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/fsl/fsl_ssi.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index ce18518add3d..46f574895f73 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -134,11 +134,12 @@ struct fsl_ssi_private {
struct device_attribute dev_attr;
struct platform_device *pdev;
- unsigned long sysrate;
bool new_binding;
bool ssi_on_imx;
bool use_dual_fifo;
+ bool baudclk_locked;
u8 i2s_mode;
+ spinlock_t baudclk_lock;
struct clk *coreclk;
struct clk *clk;
struct snd_dmaengine_dai_dma_data dma_params_tx;
@@ -330,6 +331,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct fsl_ssi_private *ssi_private =
snd_soc_dai_get_drvdata(rtd->cpu_dai);
int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+ unsigned long flags;
if (ssi_private->ssi_on_imx) {
pm_runtime_get_sync(dai->dev);
@@ -428,6 +430,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* this is bad is because at this point, the PCM driver has not
* finished initializing the DMA controller.
*/
+
+ spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+ ssi_private->baudclk_locked = false;
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
}
return 0;
@@ -456,7 +462,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
unsigned int channels = params_channels(hw_params);
- int ret;
/*
* If we're in synchronous mode, and the SSI is already enabled,
@@ -465,14 +470,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
if (enabled && ssi_private->cpu_dai_drv.symmetric_rates)
return 0;
- if (ssi_private->sysrate) {
- ret = clk_set_rate(ssi_private->clk, ssi_private->sysrate);
- if (ret) {
- dev_err(cpu_dai->dev, "failed to set clock rate\n");
- return ret;
- }
- }
-
/*
* FIXME: The documentation says that SxCCR[WL] should not be
* modified while the SSI is enabled. The only time this can
@@ -511,6 +508,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ unsigned long flags;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -538,8 +536,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RDMAE, 0);
}
- if ((read_ssi(&ssi->scr) & (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0)
+ if ((read_ssi(&ssi->scr) & (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) {
write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
+ spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+ ssi_private->baudclk_locked = false;
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+ }
break;
default:
@@ -669,9 +671,9 @@ static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+ int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
- unsigned long clkrate, sysrate = 0;
+ unsigned long clkrate, sysrate = 0, baudrate, flags;
u64 sub, savesub = 100000;
/*
@@ -708,7 +710,7 @@ static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
do_div(sub, freq);
if (sub < savesub) {
- ssi_private->sysrate = sysrate;
+ baudrate = sysrate;
savesub = sub;
pm = i;
}
@@ -734,6 +736,18 @@ static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
else
write_ssi_mask(&ssi->srccr, mask, stccr);
+ spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+ if (!ssi_private->baudclk_locked) {
+ ret = clk_set_rate(ssi_private->clk, baudrate);
+ if (ret) {
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+ dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
+ return -EINVAL;
+ }
+ ssi_private->baudclk_locked = true;
+ }
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+
return 0;
}
@@ -775,8 +789,6 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
write_ssi_mask(&ssi->sier, SIER_FLAGS, 0);
-
- ssi_private->sysrate = 0;
}
if (ssi_private->ssi_on_imx) {
@@ -974,6 +986,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
/* Older 8610 DTs didn't have the fifo-depth property */
ssi_private->fifo_depth = 8;
+ ssi_private->baudclk_locked = false;
+ spin_lock_init(&ssi_private->baudclk_lock);
+
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
ssi_private->ssi_on_imx = true;
@@ -1004,8 +1019,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
}
- ssi_private->sysrate = 0;
-
/* Initialize the the device_attribute structure */
dev_attr = &ssi_private->dev_attr;
sysfs_attr_init(&dev_attr->attr);