diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/fsl/fsl_spdif.c | 81 |
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 | ||
401 | clk_set_bypass: | 404 | clk_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 | ||
1075 | out: | ||
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 | } |