aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/fsl/fsl_spdif.c47
-rw-r--r--sound/soc/fsl/fsl_spdif.h2
2 files changed, 44 insertions, 5 deletions
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 6452ca83d889..6df70a976c10 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -80,6 +80,8 @@ struct fsl_spdif_priv {
u8 rxclk_src;
struct clk *txclk[SPDIF_TXRATE_MAX];
struct clk *rxclk;
+ struct clk *coreclk;
+ struct clk *sysclk;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -382,6 +384,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ /* Don't mess up the clocks from other modules */
+ if (clk != STC_TXCLK_SPDIF_ROOT)
+ goto clk_set_bypass;
+
/*
* The S/PDIF block needs a clock of 64 * fs * div. The S/PDIF block
* will divide by (div). So request 64 * fs * (div+1) which will
@@ -393,6 +399,7 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
return ret;
}
+clk_set_bypass:
dev_dbg(&pdev->dev, "expected clock rate = %d\n",
(64 * sample_rate * div));
dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
@@ -423,10 +430,16 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
/* Reset module and interrupts only for first initialization */
if (!cpu_dai->active) {
+ ret = clk_prepare_enable(spdif_priv->coreclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable core clock\n");
+ return ret;
+ }
+
ret = spdif_softreset(spdif_priv);
if (ret) {
dev_err(&pdev->dev, "failed to soft reset\n");
- return ret;
+ goto err;
}
/* Disable all the interrupts */
@@ -454,6 +467,11 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream,
regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
return 0;
+
+err:
+ clk_disable_unprepare(spdif_priv->coreclk);
+
+ return ret;
}
static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
@@ -484,6 +502,7 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
spdif_intr_status_clear(spdif_priv);
regmap_update_bits(regmap, REG_SPDIF_SCR,
SCR_LOW_POWER, SCR_LOW_POWER);
+ clk_disable_unprepare(spdif_priv->coreclk);
}
}
@@ -754,7 +773,7 @@ static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) {
/* Get bus clock from system */
- busclk_freq = clk_get_rate(spdif_priv->rxclk);
+ busclk_freq = clk_get_rate(spdif_priv->sysclk);
}
/* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
@@ -997,7 +1016,7 @@ static struct regmap_config fsl_spdif_regmap_config = {
static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
struct clk *clk, u64 savesub,
- enum spdif_txrate index)
+ enum spdif_txrate index, bool round)
{
const u32 rate[] = { 32000, 44100, 48000 };
u64 rate_ideal, rate_actual, sub;
@@ -1005,7 +1024,10 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
for (div = 1; div <= 128; div++) {
rate_ideal = rate[index] * (div + 1) * 64;
- rate_actual = clk_round_rate(clk, rate_ideal);
+ if (round)
+ rate_actual = clk_round_rate(clk, rate_ideal);
+ else
+ rate_actual = clk_get_rate(clk);
arate = rate_actual / 64;
arate /= div;
@@ -1058,7 +1080,8 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
if (!clk_get_rate(clk))
continue;
- ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index);
+ ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index,
+ i == STC_TXCLK_SPDIF_ROOT);
if (savesub == ret)
continue;
@@ -1134,6 +1157,20 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return ret;
}
+ /* Get system clock for rx clock rate calculation */
+ spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5");
+ if (IS_ERR(spdif_priv->sysclk)) {
+ dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n");
+ return PTR_ERR(spdif_priv->sysclk);
+ }
+
+ /* Get core clock for data register access via DMA */
+ spdif_priv->coreclk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(spdif_priv->coreclk)) {
+ dev_err(&pdev->dev, "no core clock in devicetree\n");
+ return PTR_ERR(spdif_priv->coreclk);
+ }
+
/* Select clock source for rx/tx clock */
spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
if (IS_ERR(spdif_priv->rxclk)) {
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
index 605a10b2112b..4ec27fcebac7 100644
--- a/sound/soc/fsl/fsl_spdif.h
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -157,6 +157,8 @@ enum spdif_gainsel {
#define STC_TXCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK)
#define STC_TXCLK_SRC_MAX 8
+#define STC_TXCLK_SPDIF_ROOT 1
+
/* SPDIF tx rate */
enum spdif_txrate {
SPDIF_TXRATE_32000 = 0,