aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorNicolin Chen <Guangyu.Chen@freescale.com>2014-04-18 06:11:16 -0400
committerNicolin Chen <Guangyu.Chen@freescale.com>2014-04-21 23:57:53 -0400
commit3092f062768d7c4312c54c7ec2c5f9acfbbf7e69 (patch)
treee13992dc4ed952553c32d6d3ba678bc0433a8ed1 /sound/soc/fsl
parent7e9a6bb3eb4df21f96a6f3efd1f3a334a910b2ac (diff)
ENGR00309468-2 ASoC: fsl_spdif: Add sysclk_df divsor support for sysclk usage
The sysclk, which could be connected to IPG clock, is one of the eight clocks on the inner clock mux of SPDIF. Previously we forbade the usage of this clock due to imperfect clock selecting function. This patch adds the sysclk_df divisor so as to complete sysclk function. [ In order to potect those clocks from other modules and the situation when SPDIF root clock is shared with other module (ASRC on imx6sx for example) that demands us to fix the clock and not to change its rate, starting from now on, we no longer use clk_round() and clk_set_rate(). ] Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/fsl_spdif.c89
1 files changed, 47 insertions, 42 deletions
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 4f42bb7ea6a4..c1baba2ca029 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -78,6 +78,7 @@ struct fsl_spdif_priv {
78 struct regmap *regmap; 78 struct regmap *regmap;
79 bool dpll_locked; 79 bool dpll_locked;
80 u8 txclk_div[SPDIF_TXRATE_MAX]; 80 u8 txclk_div[SPDIF_TXRATE_MAX];
81 u8 sysclk_df[SPDIF_TXRATE_MAX];
81 u8 txclk_src[SPDIF_TXRATE_MAX]; 82 u8 txclk_src[SPDIF_TXRATE_MAX];
82 u8 rxclk_src; 83 u8 rxclk_src;
83 struct clk *txclk[SPDIF_TXRATE_MAX]; 84 struct clk *txclk[SPDIF_TXRATE_MAX];
@@ -354,8 +355,7 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
354 struct platform_device *pdev = spdif_priv->pdev; 355 struct platform_device *pdev = spdif_priv->pdev;
355 unsigned long csfs = 0; 356 unsigned long csfs = 0;
356 u32 stc, mask, rate; 357 u32 stc, mask, rate;
357 u8 clk, div; 358 u8 clk, div, df;
358 int ret;
359 359
360 switch (sample_rate) { 360 switch (sample_rate) {
361 case 32000: 361 case 32000:
@@ -387,19 +387,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
387 return -EINVAL; 387 return -EINVAL;
388 } 388 }
389 389
390 /* 390 df = spdif_priv->sysclk_df[rate];
391 * The S/PDIF block needs a clock of 64 * fs * div. The S/PDIF block
392 * will divide by (div). So request 64 * fs * (div+1) which will
393 * get rounded.
394 */
395 ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1));
396 if (ret) {
397 dev_err(&pdev->dev, "failed to set tx clock rate\n");
398 return ret;
399 }
400 391
401 dev_dbg(&pdev->dev, "expected clock rate = %d\n", 392 dev_dbg(&pdev->dev, "expected clock rate = %d\n",
402 (64 * sample_rate * div)); 393 (64 * sample_rate * div * df));
403 dev_dbg(&pdev->dev, "actual clock rate = %ld\n", 394 dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
404 clk_get_rate(spdif_priv->txclk[rate])); 395 clk_get_rate(spdif_priv->txclk[rate]));
405 396
@@ -411,6 +402,13 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
411 mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK; 402 mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK;
412 regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); 403 regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);
413 404
405 /* The min of df should be 2 if valid */
406 if (df >= 2) {
407 regmap_update_bits(regmap, REG_SPDIF_STC,
408 STC_SYSCLK_DIV_MASK, STC_SYSCLK_DIV(df));
409 dev_dbg(&pdev->dev, "use df %d clk %d\n", df, clk);
410 }
411
414 dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate); 412 dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate);
415 413
416 return 0; 414 return 0;
@@ -1013,40 +1011,51 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
1013 enum spdif_txrate index) 1011 enum spdif_txrate index)
1014{ 1012{
1015 const u32 rate[] = { 32000, 44100, 48000 }; 1013 const u32 rate[] = { 32000, 44100, 48000 };
1016 u64 rate_ideal, rate_actual, sub; 1014 bool is_sysclk = clk == spdif_priv->sysclk;
1015 u64 rate_actual, sub;
1016 u32 df_min, df_max, df;
1017 u32 div, arate; 1017 u32 div, arate;
1018 1018
1019 for (div = 1; div <= 128; div++) { 1019 /* The sysclk has an extra divisor [2, 512] */
1020 rate_ideal = rate[index] * (div + 1) * 64; 1020 df_min = is_sysclk ? 2 : 1;
1021 rate_actual = clk_round_rate(clk, rate_ideal); 1021 df_max = is_sysclk ? 512 : 1;
1022 1022
1023 arate = rate_actual / 64; 1023 for (df = df_min; df <= df_max; df++) {
1024 arate /= div; 1024 for (div = 1; div <= 128; div++) {
1025 rate_actual = clk_get_rate(clk);
1025 1026
1026 if (arate == rate[index]) { 1027 arate = rate_actual / 64;
1027 /* We are lucky */ 1028 arate /= df * div;
1028 savesub = 0; 1029
1029 spdif_priv->txclk_div[index] = div; 1030 if (arate == rate[index]) {
1030 break; 1031 /* We are lucky */
1031 } else if (arate / rate[index] == 1) { 1032 savesub = 0;
1032 /* A little bigger than expect */ 1033 spdif_priv->txclk_div[index] = div;
1033 sub = (arate - rate[index]) * 100000; 1034 spdif_priv->sysclk_df[index] = df;
1034 do_div(sub, rate[index]); 1035 goto out;
1035 if (sub < savesub) { 1036 } else if (arate / rate[index] == 1) {
1037 /* A little bigger than expect */
1038 sub = (arate - rate[index]) * 100000;
1039 do_div(sub, rate[index]);
1040 if (sub >= savesub)
1041 continue;
1036 savesub = sub; 1042 savesub = sub;
1037 spdif_priv->txclk_div[index] = div; 1043 spdif_priv->txclk_div[index] = div;
1038 } 1044 spdif_priv->sysclk_df[index] = df;
1039 } else if (rate[index] / arate == 1) { 1045 } else if (rate[index] / arate == 1) {
1040 /* A little smaller than expect */ 1046 /* A little smaller than expect */
1041 sub = (rate[index] - arate) * 100000; 1047 sub = (rate[index] - arate) * 100000;
1042 do_div(sub, rate[index]); 1048 do_div(sub, rate[index]);
1043 if (sub < savesub) { 1049 if (sub >= savesub)
1050 continue;
1044 savesub = sub; 1051 savesub = sub;
1045 spdif_priv->txclk_div[index] = div; 1052 spdif_priv->txclk_div[index] = div;
1053 spdif_priv->sysclk_df[index] = df;
1046 } 1054 }
1047 } 1055 }
1048 } 1056 }
1049 1057
1058out:
1050 return savesub; 1059 return savesub;
1051} 1060}
1052 1061
@@ -1071,13 +1080,6 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
1071 if (!clk_get_rate(clk)) 1080 if (!clk_get_rate(clk))
1072 continue; 1081 continue;
1073 1082
1074 /* TODO: We here ignore sysclk source due to imperfect clock
1075 * selecting mechanism: sysclk is a bit different which we can
1076 * not change its clock rate but use another inner divider to
1077 * derive a proper clock rate. */
1078 if (i == SPDIF_CLK_SRC_SYSCLK)
1079 continue;
1080
1081 ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index); 1083 ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index);
1082 if (savesub == ret) 1084 if (savesub == ret)
1083 continue; 1085 continue;
@@ -1095,6 +1097,9 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
1095 spdif_priv->txclk_src[index], rate[index]); 1097 spdif_priv->txclk_src[index], rate[index]);
1096 dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate\n", 1098 dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate\n",
1097 spdif_priv->txclk_div[index], rate[index]); 1099 spdif_priv->txclk_div[index], rate[index]);
1100 if (spdif_priv->txclk[index] == spdif_priv->sysclk)
1101 dev_dbg(&pdev->dev, "use sysclk_df %d for %dHz sample rate\n",
1102 spdif_priv->sysclk_df[index], rate[index]);
1098 1103
1099 return 0; 1104 return 0;
1100} 1105}