diff options
author | Nicolin Chen <Guangyu.Chen@freescale.com> | 2014-01-06 03:43:19 -0500 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:47:38 -0400 |
commit | 1f5e453015ae9881c9bede2fcbf62a4ab3a15f4b (patch) | |
tree | d0b958d195171a0887707577288f2b28c551419f | |
parent | 3d184d6f16500c70699df6e9a610af74a96e3955 (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>
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 49 |
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 { | |||
134 | struct device_attribute dev_attr; | 134 | struct device_attribute dev_attr; |
135 | struct platform_device *pdev; | 135 | struct platform_device *pdev; |
136 | 136 | ||
137 | unsigned long sysrate; | ||
138 | bool new_binding; | 137 | bool new_binding; |
139 | bool ssi_on_imx; | 138 | bool ssi_on_imx; |
140 | bool use_dual_fifo; | 139 | bool use_dual_fifo; |
140 | bool baudclk_locked; | ||
141 | u8 i2s_mode; | 141 | u8 i2s_mode; |
142 | spinlock_t baudclk_lock; | ||
142 | struct clk *coreclk; | 143 | struct clk *coreclk; |
143 | struct clk *clk; | 144 | struct clk *clk; |
144 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 145 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
@@ -330,6 +331,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
330 | struct fsl_ssi_private *ssi_private = | 331 | struct fsl_ssi_private *ssi_private = |
331 | snd_soc_dai_get_drvdata(rtd->cpu_dai); | 332 | snd_soc_dai_get_drvdata(rtd->cpu_dai); |
332 | int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; | 333 | int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; |
334 | unsigned long flags; | ||
333 | 335 | ||
334 | if (ssi_private->ssi_on_imx) { | 336 | if (ssi_private->ssi_on_imx) { |
335 | pm_runtime_get_sync(dai->dev); | 337 | pm_runtime_get_sync(dai->dev); |
@@ -428,6 +430,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
428 | * this is bad is because at this point, the PCM driver has not | 430 | * this is bad is because at this point, the PCM driver has not |
429 | * finished initializing the DMA controller. | 431 | * finished initializing the DMA controller. |
430 | */ | 432 | */ |
433 | |||
434 | spin_lock_irqsave(&ssi_private->baudclk_lock, flags); | ||
435 | ssi_private->baudclk_locked = false; | ||
436 | spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags); | ||
431 | } | 437 | } |
432 | 438 | ||
433 | return 0; | 439 | return 0; |
@@ -456,7 +462,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, | |||
456 | u32 wl = CCSR_SSI_SxCCR_WL(sample_size); | 462 | u32 wl = CCSR_SSI_SxCCR_WL(sample_size); |
457 | int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN; | 463 | int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN; |
458 | unsigned int channels = params_channels(hw_params); | 464 | unsigned int channels = params_channels(hw_params); |
459 | int ret; | ||
460 | 465 | ||
461 | /* | 466 | /* |
462 | * If we're in synchronous mode, and the SSI is already enabled, | 467 | * 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, | |||
465 | if (enabled && ssi_private->cpu_dai_drv.symmetric_rates) | 470 | if (enabled && ssi_private->cpu_dai_drv.symmetric_rates) |
466 | return 0; | 471 | return 0; |
467 | 472 | ||
468 | if (ssi_private->sysrate) { | ||
469 | ret = clk_set_rate(ssi_private->clk, ssi_private->sysrate); | ||
470 | if (ret) { | ||
471 | dev_err(cpu_dai->dev, "failed to set clock rate\n"); | ||
472 | return ret; | ||
473 | } | ||
474 | } | ||
475 | |||
476 | /* | 473 | /* |
477 | * FIXME: The documentation says that SxCCR[WL] should not be | 474 | * FIXME: The documentation says that SxCCR[WL] should not be |
478 | * modified while the SSI is enabled. The only time this can | 475 | * 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, | |||
511 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 508 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
512 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); | 509 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
513 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 510 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
511 | unsigned long flags; | ||
514 | 512 | ||
515 | switch (cmd) { | 513 | switch (cmd) { |
516 | case SNDRV_PCM_TRIGGER_START: | 514 | case SNDRV_PCM_TRIGGER_START: |
@@ -538,8 +536,12 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
538 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0); | 536 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0); |
539 | write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RDMAE, 0); | 537 | write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RDMAE, 0); |
540 | } | 538 | } |
541 | if ((read_ssi(&ssi->scr) & (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) | 539 | if ((read_ssi(&ssi->scr) & (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) { |
542 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); | 540 | write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); |
541 | spin_lock_irqsave(&ssi_private->baudclk_lock, flags); | ||
542 | ssi_private->baudclk_locked = false; | ||
543 | spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags); | ||
544 | } | ||
543 | break; | 545 | break; |
544 | 546 | ||
545 | default: | 547 | default: |
@@ -669,9 +671,9 @@ static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
669 | { | 671 | { |
670 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); | 672 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); |
671 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 673 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
672 | int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; | 674 | int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret; |
673 | u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i; | 675 | u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i; |
674 | unsigned long clkrate, sysrate = 0; | 676 | unsigned long clkrate, sysrate = 0, baudrate, flags; |
675 | u64 sub, savesub = 100000; | 677 | u64 sub, savesub = 100000; |
676 | 678 | ||
677 | /* | 679 | /* |
@@ -708,7 +710,7 @@ static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
708 | do_div(sub, freq); | 710 | do_div(sub, freq); |
709 | 711 | ||
710 | if (sub < savesub) { | 712 | if (sub < savesub) { |
711 | ssi_private->sysrate = sysrate; | 713 | baudrate = sysrate; |
712 | savesub = sub; | 714 | savesub = sub; |
713 | pm = i; | 715 | pm = i; |
714 | } | 716 | } |
@@ -734,6 +736,18 @@ static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
734 | else | 736 | else |
735 | write_ssi_mask(&ssi->srccr, mask, stccr); | 737 | write_ssi_mask(&ssi->srccr, mask, stccr); |
736 | 738 | ||
739 | spin_lock_irqsave(&ssi_private->baudclk_lock, flags); | ||
740 | if (!ssi_private->baudclk_locked) { | ||
741 | ret = clk_set_rate(ssi_private->clk, baudrate); | ||
742 | if (ret) { | ||
743 | spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags); | ||
744 | dev_err(cpu_dai->dev, "failed to set baudclk rate\n"); | ||
745 | return -EINVAL; | ||
746 | } | ||
747 | ssi_private->baudclk_locked = true; | ||
748 | } | ||
749 | spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags); | ||
750 | |||
737 | return 0; | 751 | return 0; |
738 | } | 752 | } |
739 | 753 | ||
@@ -775,8 +789,6 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, | |||
775 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 789 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
776 | 790 | ||
777 | write_ssi_mask(&ssi->sier, SIER_FLAGS, 0); | 791 | write_ssi_mask(&ssi->sier, SIER_FLAGS, 0); |
778 | |||
779 | ssi_private->sysrate = 0; | ||
780 | } | 792 | } |
781 | 793 | ||
782 | if (ssi_private->ssi_on_imx) { | 794 | if (ssi_private->ssi_on_imx) { |
@@ -974,6 +986,9 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
974 | /* Older 8610 DTs didn't have the fifo-depth property */ | 986 | /* Older 8610 DTs didn't have the fifo-depth property */ |
975 | ssi_private->fifo_depth = 8; | 987 | ssi_private->fifo_depth = 8; |
976 | 988 | ||
989 | ssi_private->baudclk_locked = false; | ||
990 | spin_lock_init(&ssi_private->baudclk_lock); | ||
991 | |||
977 | if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) { | 992 | if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) { |
978 | ssi_private->ssi_on_imx = true; | 993 | ssi_private->ssi_on_imx = true; |
979 | 994 | ||
@@ -1004,8 +1019,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1004 | ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0); | 1019 | ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0); |
1005 | } | 1020 | } |
1006 | 1021 | ||
1007 | ssi_private->sysrate = 0; | ||
1008 | |||
1009 | /* Initialize the the device_attribute structure */ | 1022 | /* Initialize the the device_attribute structure */ |
1010 | dev_attr = &ssi_private->dev_attr; | 1023 | dev_attr = &ssi_private->dev_attr; |
1011 | sysfs_attr_init(&dev_attr->attr); | 1024 | sysfs_attr_init(&dev_attr->attr); |