aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorMarkus Pargmann <mpa@pengutronix.de>2014-05-27 04:24:23 -0400
committerMark Brown <broonie@linaro.org>2014-06-01 06:55:08 -0400
commitd429d8e3324cae120784a1e194ef6ea62aeb327e (patch)
tree1e1e30653ce73b844e2d8d36c1e8d9b1dcca827a /sound/soc/fsl
parentb5dd91b3dcf937ce42583711fe4d679cacdbd2d0 (diff)
ASoC: fsl-ssi: Fix baudclock handling
The baudclock may be used and set by different streams. Allow only the first stream to set the bitclock rate. Other streams have to try to get to the correct rate without modifying the bitclock rate using the SSI internal clock modifiers. The variable baudclk_streams is introduced to keep track of the active streams that are using the baudclock. This way we know if the baudclock may be set and whether we may enable/disable the clock. baudclock enable/disable is moved to hw_params()/hw_free(). This way we can keep track of the baudclock in those two functions and avoid a running clock while it is not used. As hw_params()/hw_free() may be called multiple times for the same stream, we have to use baudclk_streams variable to know whether we may enable/disable the clock. Signed-off-by: Markus Pargmann <mpa@pengutronix.de> Tested-By: Michael Grzeschik <mgr@pengutronix.de> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/fsl_ssi.c62
1 files changed, 41 insertions, 21 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index dbcde106adca..ac786601b9d6 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -160,11 +160,11 @@ struct fsl_ssi_private {
160 unsigned int dai_fmt; 160 unsigned int dai_fmt;
161 161
162 bool use_dma; 162 bool use_dma;
163 bool baudclk_locked;
164 bool use_dual_fifo; 163 bool use_dual_fifo;
165 u8 i2s_mode; 164 u8 i2s_mode;
166 struct clk *baudclk; 165 struct clk *baudclk;
167 struct clk *clk; 166 struct clk *clk;
167 unsigned int baudclk_streams;
168 unsigned int bitclk_freq; 168 unsigned int bitclk_freq;
169 struct snd_dmaengine_dai_dma_data dma_params_tx; 169 struct snd_dmaengine_dai_dma_data dma_params_tx;
170 struct snd_dmaengine_dai_dma_data dma_params_rx; 170 struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -495,9 +495,6 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
495 struct fsl_ssi_private *ssi_private = 495 struct fsl_ssi_private *ssi_private =
496 snd_soc_dai_get_drvdata(rtd->cpu_dai); 496 snd_soc_dai_get_drvdata(rtd->cpu_dai);
497 497
498 if (!dai->active && !fsl_ssi_is_ac97(ssi_private))
499 ssi_private->baudclk_locked = false;
500
501 /* When using dual fifo mode, it is safer to ensure an even period 498 /* When using dual fifo mode, it is safer to ensure an even period
502 * size. If appearing to an odd number while DMA always starts its 499 * size. If appearing to an odd number while DMA always starts its
503 * task from fifo0, fifo1 would be neglected at the end of each 500 * task from fifo0, fifo1 would be neglected at the end of each
@@ -530,6 +527,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
530 unsigned long clkrate, baudrate, tmprate; 527 unsigned long clkrate, baudrate, tmprate;
531 u64 sub, savesub = 100000; 528 u64 sub, savesub = 100000;
532 unsigned int freq; 529 unsigned int freq;
530 bool baudclk_is_used;
533 531
534 /* Prefer the explicitly set bitclock frequency */ 532 /* Prefer the explicitly set bitclock frequency */
535 if (ssi_private->bitclk_freq) 533 if (ssi_private->bitclk_freq)
@@ -541,6 +539,8 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
541 if (IS_ERR(ssi_private->baudclk)) 539 if (IS_ERR(ssi_private->baudclk))
542 return -EINVAL; 540 return -EINVAL;
543 541
542 baudclk_is_used = ssi_private->baudclk_streams & ~(BIT(substream->stream));
543
544 /* It should be already enough to divide clock by setting pm alone */ 544 /* It should be already enough to divide clock by setting pm alone */
545 psr = 0; 545 psr = 0;
546 div2 = 0; 546 div2 = 0;
@@ -553,7 +553,11 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
553 continue; 553 continue;
554 554
555 tmprate = freq * factor * (i + 2); 555 tmprate = freq * factor * (i + 2);
556 clkrate = clk_round_rate(ssi_private->baudclk, tmprate); 556
557 if (baudclk_is_used)
558 clkrate = clk_get_rate(ssi_private->baudclk);
559 else
560 clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
557 561
558 do_div(clkrate, factor); 562 do_div(clkrate, factor);
559 afreq = (u32)clkrate / (i + 1); 563 afreq = (u32)clkrate / (i + 1);
@@ -598,13 +602,12 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
598 else 602 else
599 write_ssi_mask(&ssi->srccr, mask, stccr); 603 write_ssi_mask(&ssi->srccr, mask, stccr);
600 604
601 if (!ssi_private->baudclk_locked) { 605 if (!baudclk_is_used) {
602 ret = clk_set_rate(ssi_private->baudclk, baudrate); 606 ret = clk_set_rate(ssi_private->baudclk, baudrate);
603 if (ret) { 607 if (ret) {
604 dev_err(cpu_dai->dev, "failed to set baudclk rate\n"); 608 dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
605 return -EINVAL; 609 return -EINVAL;
606 } 610 }
607 ssi_private->baudclk_locked = true;
608 } 611 }
609 612
610 return 0; 613 return 0;
@@ -656,6 +659,15 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
656 ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params); 659 ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params);
657 if (ret) 660 if (ret)
658 return ret; 661 return ret;
662
663 /* Do not enable the clock if it is already enabled */
664 if (!(ssi_private->baudclk_streams & BIT(substream->stream))) {
665 ret = clk_prepare_enable(ssi_private->baudclk);
666 if (ret)
667 return ret;
668
669 ssi_private->baudclk_streams |= BIT(substream->stream);
670 }
659 } 671 }
660 672
661 /* 673 /*
@@ -683,6 +695,22 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
683 return 0; 695 return 0;
684} 696}
685 697
698static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,
699 struct snd_soc_dai *cpu_dai)
700{
701 struct snd_soc_pcm_runtime *rtd = substream->private_data;
702 struct fsl_ssi_private *ssi_private =
703 snd_soc_dai_get_drvdata(rtd->cpu_dai);
704
705 if (fsl_ssi_is_i2s_master(ssi_private) &&
706 ssi_private->baudclk_streams & BIT(substream->stream)) {
707 clk_disable_unprepare(ssi_private->baudclk);
708 ssi_private->baudclk_streams &= ~BIT(substream->stream);
709 }
710
711 return 0;
712}
713
686static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, 714static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private,
687 unsigned int fmt) 715 unsigned int fmt)
688{ 716{
@@ -692,6 +720,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private,
692 720
693 ssi_private->dai_fmt = fmt; 721 ssi_private->dai_fmt = fmt;
694 722
723 if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) {
724 dev_err(&ssi_private->pdev->dev, "baudclk is missing which is necessary for master mode\n");
725 return -EINVAL;
726 }
727
695 fsl_ssi_setup_reg_vals(ssi_private); 728 fsl_ssi_setup_reg_vals(ssi_private);
696 729
697 scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK); 730 scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
@@ -912,11 +945,6 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
912 fsl_ssi_tx_config(ssi_private, false); 945 fsl_ssi_tx_config(ssi_private, false);
913 else 946 else
914 fsl_ssi_rx_config(ssi_private, false); 947 fsl_ssi_rx_config(ssi_private, false);
915
916 if (!fsl_ssi_is_ac97(ssi_private) && (read_ssi(&ssi->scr) &
917 (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0)
918 ssi_private->baudclk_locked = false;
919
920 break; 948 break;
921 949
922 default: 950 default:
@@ -948,6 +976,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
948static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { 976static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
949 .startup = fsl_ssi_startup, 977 .startup = fsl_ssi_startup,
950 .hw_params = fsl_ssi_hw_params, 978 .hw_params = fsl_ssi_hw_params,
979 .hw_free = fsl_ssi_hw_free,
951 .set_fmt = fsl_ssi_set_dai_fmt, 980 .set_fmt = fsl_ssi_set_dai_fmt,
952 .set_sysclk = fsl_ssi_set_dai_sysclk, 981 .set_sysclk = fsl_ssi_set_dai_sysclk,
953 .set_tdm_slot = fsl_ssi_set_dai_tdm_slot, 982 .set_tdm_slot = fsl_ssi_set_dai_tdm_slot,
@@ -1087,8 +1116,6 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
1087 if (IS_ERR(ssi_private->baudclk)) 1116 if (IS_ERR(ssi_private->baudclk))
1088 dev_dbg(&pdev->dev, "could not get baud clock: %ld\n", 1117 dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
1089 PTR_ERR(ssi_private->baudclk)); 1118 PTR_ERR(ssi_private->baudclk));
1090 else
1091 clk_prepare_enable(ssi_private->baudclk);
1092 1119
1093 /* 1120 /*
1094 * We have burstsize be "fifo_depth - 2" to match the SSI 1121 * We have burstsize be "fifo_depth - 2" to match the SSI
@@ -1139,9 +1166,6 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
1139 return 0; 1166 return 0;
1140 1167
1141error_pcm: 1168error_pcm:
1142 if (!IS_ERR(ssi_private->baudclk))
1143 clk_disable_unprepare(ssi_private->baudclk);
1144
1145 clk_disable_unprepare(ssi_private->clk); 1169 clk_disable_unprepare(ssi_private->clk);
1146 1170
1147 return ret; 1171 return ret;
@@ -1152,8 +1176,6 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
1152{ 1176{
1153 if (!ssi_private->use_dma) 1177 if (!ssi_private->use_dma)
1154 imx_pcm_fiq_exit(pdev); 1178 imx_pcm_fiq_exit(pdev);
1155 if (!IS_ERR(ssi_private->baudclk))
1156 clk_disable_unprepare(ssi_private->baudclk);
1157 clk_disable_unprepare(ssi_private->clk); 1179 clk_disable_unprepare(ssi_private->clk);
1158} 1180}
1159 1181
@@ -1248,8 +1270,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
1248 /* Older 8610 DTs didn't have the fifo-depth property */ 1270 /* Older 8610 DTs didn't have the fifo-depth property */
1249 ssi_private->fifo_depth = 8; 1271 ssi_private->fifo_depth = 8;
1250 1272
1251 ssi_private->baudclk_locked = false;
1252
1253 dev_set_drvdata(&pdev->dev, ssi_private); 1273 dev_set_drvdata(&pdev->dev, ssi_private);
1254 1274
1255 if (ssi_private->soc->imx) { 1275 if (ssi_private->soc->imx) {