aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl/fsl_spdif.c
diff options
context:
space:
mode:
authorNicolin Chen <Guangyu.Chen@freescale.com>2014-04-30 06:54:07 -0400
committerMark Brown <broonie@linaro.org>2014-05-05 15:27:39 -0400
commit27c647bff20c6883dd0b4e3fc24c3d414a9e192a (patch)
tree29c7e4ffd900be5554191563c9d9a8e89d4117c9 /sound/soc/fsl/fsl_spdif.c
parente41a4a79af5cad172971af8681292af33496b119 (diff)
ASoC: fsl_spdif: Add sysclk df support to derive txclk from sysclk
The sysclk is one the clock sources that could be selected to derive tx clock. But the route for sysclk is a bit different that it does not only contain txclk df divider but also have an extra sysclk df. So this patch mainly adds syclk df configuration support so as to let the driver be able to get clock from sysclk. Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/fsl/fsl_spdif.c')
-rw-r--r--sound/soc/fsl/fsl_spdif.c81
1 files changed, 51 insertions, 30 deletions
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index abd669e233eb..1a92d7fe1a86 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -76,6 +76,7 @@ struct fsl_spdif_priv {
76 struct regmap *regmap; 76 struct regmap *regmap;
77 bool dpll_locked; 77 bool dpll_locked;
78 u8 txclk_df[SPDIF_TXRATE_MAX]; 78 u8 txclk_df[SPDIF_TXRATE_MAX];
79 u8 sysclk_df[SPDIF_TXRATE_MAX];
79 u8 txclk_src[SPDIF_TXRATE_MAX]; 80 u8 txclk_src[SPDIF_TXRATE_MAX];
80 u8 rxclk_src; 81 u8 rxclk_src;
81 struct clk *txclk[SPDIF_TXRATE_MAX]; 82 struct clk *txclk[SPDIF_TXRATE_MAX];
@@ -351,7 +352,7 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
351 struct platform_device *pdev = spdif_priv->pdev; 352 struct platform_device *pdev = spdif_priv->pdev;
352 unsigned long csfs = 0; 353 unsigned long csfs = 0;
353 u32 stc, mask, rate; 354 u32 stc, mask, rate;
354 u8 clk, txclk_df; 355 u8 clk, txclk_df, sysclk_df;
355 int ret; 356 int ret;
356 357
357 switch (sample_rate) { 358 switch (sample_rate) {
@@ -384,6 +385,8 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
384 return -EINVAL; 385 return -EINVAL;
385 } 386 }
386 387
388 sysclk_df = spdif_priv->sysclk_df[rate];
389
387 /* Don't mess up the clocks from other modules */ 390 /* Don't mess up the clocks from other modules */
388 if (clk != STC_TXCLK_SPDIF_ROOT) 391 if (clk != STC_TXCLK_SPDIF_ROOT)
389 goto clk_set_bypass; 392 goto clk_set_bypass;
@@ -400,7 +403,7 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
400 403
401clk_set_bypass: 404clk_set_bypass:
402 dev_dbg(&pdev->dev, "expected clock rate = %d\n", 405 dev_dbg(&pdev->dev, "expected clock rate = %d\n",
403 (64 * sample_rate * txclk_df)); 406 (64 * sample_rate * txclk_df * sysclk_df));
404 dev_dbg(&pdev->dev, "actual clock rate = %ld\n", 407 dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
405 clk_get_rate(spdif_priv->txclk[rate])); 408 clk_get_rate(spdif_priv->txclk[rate]));
406 409
@@ -412,6 +415,9 @@ clk_set_bypass:
412 mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DF_MASK; 415 mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DF_MASK;
413 regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); 416 regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);
414 417
418 regmap_update_bits(regmap, REG_SPDIF_STC,
419 STC_SYSCLK_DF_MASK, STC_SYSCLK_DF(sysclk_df));
420
415 dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate); 421 dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate);
416 422
417 return 0; 423 return 0;
@@ -1018,43 +1024,55 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
1018 enum spdif_txrate index, bool round) 1024 enum spdif_txrate index, bool round)
1019{ 1025{
1020 const u32 rate[] = { 32000, 44100, 48000 }; 1026 const u32 rate[] = { 32000, 44100, 48000 };
1027 bool is_sysclk = clk == spdif_priv->sysclk;
1021 u64 rate_ideal, rate_actual, sub; 1028 u64 rate_ideal, rate_actual, sub;
1022 u32 txclk_df, arate; 1029 u32 sysclk_dfmin, sysclk_dfmax;
1023 1030 u32 txclk_df, sysclk_df, arate;
1024 for (txclk_df = 1; txclk_df <= 128; txclk_df++) { 1031
1025 rate_ideal = rate[index] * (txclk_df + 1) * 64; 1032 /* The sysclk has an extra divisor [2, 512] */
1026 if (round) 1033 sysclk_dfmin = is_sysclk ? 2 : 1;
1027 rate_actual = clk_round_rate(clk, rate_ideal); 1034 sysclk_dfmax = is_sysclk ? 512 : 1;
1028 else 1035
1029 rate_actual = clk_get_rate(clk); 1036 for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) {
1030 1037 for (txclk_df = 1; txclk_df <= 128; txclk_df++) {
1031 arate = rate_actual / 64; 1038 rate_ideal = rate[index] * (txclk_df + 1) * 64;
1032 arate /= txclk_df; 1039 if (round)
1033 1040 rate_actual = clk_round_rate(clk, rate_ideal);
1034 if (arate == rate[index]) { 1041 else
1035 /* We are lucky */ 1042 rate_actual = clk_get_rate(clk);
1036 savesub = 0; 1043
1037 spdif_priv->txclk_df[index] = txclk_df; 1044 arate = rate_actual / 64;
1038 break; 1045 arate /= txclk_df * sysclk_df;
1039 } else if (arate / rate[index] == 1) { 1046
1040 /* A little bigger than expect */ 1047 if (arate == rate[index]) {
1041 sub = (arate - rate[index]) * 100000; 1048 /* We are lucky */
1042 do_div(sub, rate[index]); 1049 savesub = 0;
1043 if (sub < savesub) { 1050 spdif_priv->txclk_df[index] = txclk_df;
1051 spdif_priv->sysclk_df[index] = sysclk_df;
1052 goto out;
1053 } else if (arate / rate[index] == 1) {
1054 /* A little bigger than expect */
1055 sub = (arate - rate[index]) * 100000;
1056 do_div(sub, rate[index]);
1057 if (sub >= savesub)
1058 continue;
1044 savesub = sub; 1059 savesub = sub;
1045 spdif_priv->txclk_df[index] = txclk_df; 1060 spdif_priv->txclk_df[index] = txclk_df;
1046 } 1061 spdif_priv->sysclk_df[index] = sysclk_df;
1047 } else if (rate[index] / arate == 1) { 1062 } else if (rate[index] / arate == 1) {
1048 /* A little smaller than expect */ 1063 /* A little smaller than expect */
1049 sub = (rate[index] - arate) * 100000; 1064 sub = (rate[index] - arate) * 100000;
1050 do_div(sub, rate[index]); 1065 do_div(sub, rate[index]);
1051 if (sub < savesub) { 1066 if (sub >= savesub)
1067 continue;
1052 savesub = sub; 1068 savesub = sub;
1053 spdif_priv->txclk_df[index] = txclk_df; 1069 spdif_priv->txclk_df[index] = txclk_df;
1070 spdif_priv->sysclk_df[index] = sysclk_df;
1054 } 1071 }
1055 } 1072 }
1056 } 1073 }
1057 1074
1075out:
1058 return savesub; 1076 return savesub;
1059} 1077}
1060 1078
@@ -1097,6 +1115,9 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
1097 spdif_priv->txclk_src[index], rate[index]); 1115 spdif_priv->txclk_src[index], rate[index]);
1098 dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", 1116 dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n",
1099 spdif_priv->txclk_df[index], rate[index]); 1117 spdif_priv->txclk_df[index], rate[index]);
1118 if (spdif_priv->txclk[index] == spdif_priv->sysclk)
1119 dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n",
1120 spdif_priv->sysclk_df[index], rate[index]);
1100 1121
1101 return 0; 1122 return 0;
1102} 1123}