From b164260078426fece986dc4020b8a69d9a2f6023 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Thu, 16 Apr 2020 14:43:32 +0300 Subject: MLK-23567-2 ASoC: fsl_xcvr: enable SPDIF TX Enable XCVR SPDIF TX mode. Signed-off-by: Viorel Suman Reviewed-by: Shengjiu Wang --- sound/soc/fsl/fsl_xcvr.c | 320 +++++++++++++++++++++++++++-------------------- 1 file changed, 183 insertions(+), 137 deletions(-) (limited to 'sound/soc/fsl/fsl_xcvr.c') diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 21ab428a2c7f..72b4d6b23b78 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "fsl_xcvr.h" #include "imx-pcm.h" @@ -36,6 +38,16 @@ struct fsl_xcvr { u8 cap_ds[FSL_XCVR_CAPDS_SIZE]; }; +static const struct fsl_xcvr_pll_conf { + u8 mfi; /* min=0x18, max=0x38 */ + u32 mfn; /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */ + u32 mfd; /* unsigned int */ + u32 fout; /* Fout = Fref*(MFI + MFN/MFD), Fref is 24MHz */ +} fsl_xcvr_pll_cfg[] = { + { .mfi = 32, .mfn = 96, .mfd = 125, .fout = 786432000, }, + { .mfi = 30, .mfn = 66, .mfd = 625, .fout = 722534400, }, +}; + static const u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, }; /* one bit 6, 12 ? */ static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_channels_constr = { .count = ARRAY_SIZE(fsl_xcvr_earc_channels), @@ -65,37 +77,91 @@ static const char * const fsl_xcvr_arc_mode[] = { static const struct soc_enum fsl_xcvr_arc_mode_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_arc_mode), fsl_xcvr_arc_mode); -/* - * pll_phy: pll 0; phy 1; -*/ -static int fsl_xcvr_phy_write(struct fsl_xcvr *xcvr, int reg, int data, int pll_phy) +/** phy: true => phy, false => pll */ +static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) { - int val; - int idx0, idx1; + u32 val, idx, tidx; - idx0 = pll_phy > 0 ? 26 : 24; - idx1 = pll_phy > 0 ? 24 : 26; + idx = BIT(phy ? 26 : 24); + tidx = BIT(phy ? 27 : 25); + regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF); + regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg); regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data); - regmap_read(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, &val); - - val = ((~(val & BIT(idx0))) & BIT(idx0)) | (val & BIT(idx1)) | reg | BIT(15); - - regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val); + regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx); do { regmap_read(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, &val); - } while ((val & BIT(idx0)) != ((val & BIT(idx0 + 1)) >> 1)); + } while ((val & idx) != ((val & tidx) >> 1)); return 0; } +static int fsl_xcvr_en_phy(struct fsl_xcvr *xcvr, bool earc, u32 freq) +{ + struct device *dev = &xcvr->pdev->dev; + u32 i, div = 0, log2; + + for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { + if (fsl_xcvr_pll_cfg[i].fout % freq == 0) { + div = fsl_xcvr_pll_cfg[i].fout / freq; + break; + } + } + + if (!div || i >= ARRAY_SIZE(fsl_xcvr_pll_cfg)) + return -EINVAL; + + log2 = ilog2(div); + + /* PLL: CTRL0: DIV_INTEGER */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); + /* PLL: NUMERATOR: MFN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); + /* PLL: DENOMINATOR: MFD */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); + /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); + udelay(25); + /* PLL: CTRL0: Clear Hold Ring Off */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, + FSL_XCVR_PLL_CTRL0_HROFF, 0); + udelay(100); + /* PLL: POSTDIV: PDIV0 */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, log2, 0); + /* PLL: CTRL_SET: CLKMUX0_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, + FSL_XCVR_PLL_CTRL0_CM0_EN, 0); + + if (earc) { /* eARC mode */ + /* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET, + FSL_XCVR_PHY_CTRL_TSDIFF_OE | + FSL_XCVR_PHY_CTRL_PHY_EN, 1); + /* PHY: CTRL2_SET: EARC_TX_MODE */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET, + FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1); + + } else { /* SPDIF mode */ + /* PHY: CTRL_SET: SPDIF_EN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET, + FSL_XCVR_PHY_CTRL_SPDIF_EN, 1); + } + + dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n", + freq, fsl_xcvr_pll_cfg[i].fout, fsl_xcvr_pll_cfg[i].mfi, + fsl_xcvr_pll_cfg[i].mfn, fsl_xcvr_pll_cfg[i].mfd, div, log2); + return 0; +} + static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 m_ctl = 0, v_ctl = 0, m_isr = 0, v_isr = 0; + u32 m_ctl = 0, v_ctl = 0, m_isr = 0, v_isr = 0, val; + u32 mode = xcvr->mode & FSL_XCVR_AMODE_MASK; int ret = 0; ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, @@ -106,7 +172,7 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, } /* configure EXT_CTRL */ - switch (xcvr->mode & FSL_XCVR_AMODE_MASK) { + switch (mode) { case FSL_XCVR_AMODE_SPDIF: /* set SPDIF MODE */ m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE; @@ -146,6 +212,24 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, return ret; } + if (tx && mode == FSL_XCVR_AMODE_SPDIF) { + val = FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM; + val |= FSL_XCVR_TX_DPTH_CTRL_FRM_FMT; + ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET, val); + if (ret < 0) { + dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret); + return ret; + } + } else { + /* Release M0+ reset */ + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_CORE_RESET, 0); + if (ret < 0) { + dev_err(dai->dev, "M0+ core release failed: %d\n", ret); + return ret; + } + } + return 0; } @@ -202,45 +286,6 @@ static int fsl_xcvr_startup(struct snd_pcm_substream *substream, xcvr->streams |= BIT(substream->stream); - switch (xcvr->mode & FSL_XCVR_AMODE_MASK) { - case FSL_XCVR_AMODE_SPDIF: - if (tx) { - fsl_xcvr_phy_write(xcvr, 0x54, 0x1, 0); - fsl_xcvr_phy_write(xcvr, 0x4, 0x1, 1); - fsl_xcvr_phy_write(xcvr, 0x0, 0x28, 0); - fsl_xcvr_phy_write(xcvr, 0x20, 0x60, 0); - fsl_xcvr_phy_write(xcvr, 0x30, 0x64, 0); - fsl_xcvr_phy_write(xcvr, 0x4, 0x1006000, 0); - udelay(25); - fsl_xcvr_phy_write(xcvr, 0x8, 0x2000, 0); - udelay(100); - fsl_xcvr_phy_write(xcvr, 0x40, 0x5, 0); - - fsl_xcvr_phy_write(xcvr, 0x4, 0x20, 1); - fsl_xcvr_phy_write(xcvr, 0x74, 0x4000, 1); - } - break; - case FSL_XCVR_AMODE_EARC: - if (tx) { - fsl_xcvr_phy_write(xcvr, 0x54, 0x1, 0); - fsl_xcvr_phy_write(xcvr, 0x4, 0x1, 1); - fsl_xcvr_phy_write(xcvr, 0x0, 0x28, 0); - fsl_xcvr_phy_write(xcvr, 0x20, 0x60, 0); - fsl_xcvr_phy_write(xcvr, 0x30, 0x64, 0); - fsl_xcvr_phy_write(xcvr, 0x4, 0x1006000, 0); - udelay(25); - fsl_xcvr_phy_write(xcvr, 0x8, 0x2000, 0); - udelay(100); - fsl_xcvr_phy_write(xcvr, 0x40, 0x1, 0); - - fsl_xcvr_phy_write(xcvr, 0x4, 0x20, 1); - fsl_xcvr_phy_write(xcvr, 0x74, 0x4000, 1); - } - break; - default: - break; - } - return 0; } @@ -289,53 +334,65 @@ static int fsl_xcvr_hw_params(struct snd_pcm_substream *substream, { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 mask, val, r = params_rate(params), ch = params_channels(params); - int ret; + u32 r = params_rate(params), ch = params_channels(params); + snd_pcm_format_t f = params_format(params); + u32 reg, val, bclk = 32 * r * ch; + u32 mode = xcvr->mode & FSL_XCVR_AMODE_MASK; + int i, ret; - if (tx) { - mask = FSL_XCVR_CS_DATA_0_FS_MASK; - mask |= FSL_XCVR_CS_DATA_0_CH_MASK; - - switch (r) { - case 32000: val = FSL_XCVR_CS_DATA_0_FS_32000; break; - case 44100: val = FSL_XCVR_CS_DATA_0_FS_44100; break; - case 48000: val = FSL_XCVR_CS_DATA_0_FS_48000; break; - case 64000: val = FSL_XCVR_CS_DATA_0_FS_64000; break; - case 88200: val = FSL_XCVR_CS_DATA_0_FS_88200; break; - case 96000: val = FSL_XCVR_CS_DATA_0_FS_96000; break; - case 176400: val = FSL_XCVR_CS_DATA_0_FS_176400; break; - case 192000: val = FSL_XCVR_CS_DATA_0_FS_192000; break; - default: - dev_err(dai->dev, "Unsupported rate: %u\n", r); - return -EINVAL; - } - val |= FSL_XCVR_CS_DATA_0_CH_UMLPCM; + if (!tx) + return 0; + + ret = snd_pcm_create_iec958_consumer_hw_params(params, + xcvr->tx_iec958.status, ARRAY_SIZE(xcvr->tx_iec958.status)); + if (ret < 0) { + dev_err(dai->dev, "Creating IEC958 CS failed %d\n", ret); + return ret; + } - /* Update TX CS data bits 0 */ - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_CS_DATA_0, - mask, val); + for (i = 0; i < 6; i++) { + val = (xcvr->tx_iec958.status[4 * i + 0] << 24) | + (xcvr->tx_iec958.status[4 * i + 1] << 16) | + (xcvr->tx_iec958.status[4 * i + 2] << 8) | + (xcvr->tx_iec958.status[4 * i + 3] << 0); + /* Update TX CS data bits */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_CS_DATA_0 + 4 * i, + val); if (ret < 0) { - dev_err(dai->dev, "Failed to set TX CS 0: %d\n", ret); + dev_err(dai->dev, "Failed to set TXCS%d: %d\n", i, ret); return ret; } + } - switch (ch) { - case 2: val = FSL_XCVR_CS_DATA_1_CH_2; break; - case 8: val = FSL_XCVR_CS_DATA_1_CH_8; break; - case 16: val = FSL_XCVR_CS_DATA_1_CH_16; break; - case 32: val = FSL_XCVR_CS_DATA_1_CH_32; break; - default: - dev_err(dai->dev, "Unsupported channels: %u\n", ch); - return -EINVAL; - } + switch (mode) { + case FSL_XCVR_AMODE_EARC: + bclk *= 10; + break; + case FSL_XCVR_AMODE_SPDIF: + bclk *= 2; + break; + } - /* Update TX CS data bits 1 */ - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_CS_DATA_1, - FSL_XCVR_CS_DATA_1_CH_MASK, val); - if (ret < 0) { - dev_err(dai->dev, "Failed to set TX CS 1: %d\n", ret); - return ret; - } + ret = fsl_xcvr_en_phy(xcvr, (mode == FSL_XCVR_AMODE_EARC), bclk); + if (ret < 0) { + dev_err(dai->dev, "Failed to set TX freq %u: %d\n", bclk, ret); + return ret; + } + + /* enable/disable IEC958 encoding as function of input format */ + val = FSL_XCVR_TX_DPTH_CTRL_CS_MOD; + val |= FSL_XCVR_TX_DPTH_CTRL_EN_PREAMBLE; + val |= FSL_XCVR_TX_DPTH_CTRL_EN_PARITY; + + if (f == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) + reg = FSL_XCVR_TX_DPTH_CTRL_CLR; /* disable IEC958 encoding */ + else + reg = FSL_XCVR_TX_DPTH_CTRL_SET; /* enable IEC958 encoding */ + + ret = regmap_write(xcvr->regmap, reg, val); + if (ret < 0) { + dev_err(dai->dev, "Failed to en/dis IEC958 encode: %d\n", ret); + return ret; } return 0; @@ -356,10 +413,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, switch (xcvr->mode & FSL_XCVR_AMODE_MASK) { case FSL_XCVR_AMODE_EARC: /* set isr_cmdc_tx_en, w1c */ - ret = regmap_update_bits(xcvr->regmap, - FSL_XCVR_ISR_SET, - FSL_XCVR_ISR_CMDC_TX_EN, - FSL_XCVR_ISR_CMDC_TX_EN); + ret = regmap_write(xcvr->regmap, + FSL_XCVR_ISR_SET, + FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) { dev_err(dai->dev, "err updating isr %d\n", ret); @@ -368,9 +424,8 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, /* fall through */ case FSL_XCVR_AMODE_SPDIF: - ret = regmap_update_bits(xcvr->regmap, + ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET, - FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to set TX_DPTH_CTRL_STRT_DATA_TX: %d\n", ret); @@ -378,26 +433,6 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, } break; } - } else { - /* Clear RX FIFO */ - ret = regmap_update_bits(xcvr->regmap, - FSL_XCVR_RX_DPTH_CTRL_SET, - FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO, - FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO); - if (ret < 0) { - dev_err(dai->dev, "Failed to clear RX FIFO: %d\n", ret); - return ret; - } - - /* Flip RX FIFO bits */ - ret = regmap_update_bits(xcvr->regmap, - FSL_XCVR_RX_DPTH_CTRL_SET, - FSL_XCVR_RX_DPTH_CTRL_STORE_FMT, - FSL_XCVR_RX_DPTH_CTRL_STORE_FMT); - if (ret < 0) { - dev_err(dai->dev, "Failed to set reverse bit in RX FIFO: %d\n", ret); - return ret; - } } /* enable DMA RD/WR */ @@ -423,9 +458,8 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, if (tx) { switch (xcvr->mode & FSL_XCVR_AMODE_MASK) { case FSL_XCVR_AMODE_SPDIF: - ret = regmap_update_bits(xcvr->regmap, + ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_CLR, - FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to clr TX_DPTH_CTRL_STRT_DATA_TX: %d\n", ret); @@ -434,10 +468,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, /* fall through ...*/ case FSL_XCVR_AMODE_EARC: /* clear ISR_CMDC_TX_EN, W1C */ - ret = regmap_update_bits(xcvr->regmap, - FSL_XCVR_ISR_CLR, - FSL_XCVR_ISR_CMDC_TX_EN, - FSL_XCVR_ISR_CMDC_TX_EN); + ret = regmap_write(xcvr->regmap, + FSL_XCVR_ISR_CLR, + FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) { dev_err(dai->dev, "Err updating ISR %d\n", ret); @@ -521,9 +554,29 @@ err_firmware: return ret; } + /* Flip RX FIFO bits */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET, + FSL_XCVR_RX_DPTH_CTRL_STORE_FMT); + if (ret < 0) { + dev_err(dev, "Failed to set reverse bit in RX FIFO: %d\n", ret); + return ret; + } + /* Store Capabilities Data Structure into Data RAM */ memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds, FSL_XCVR_CAPDS_SIZE); + + /* Release AI interface from reset */ + ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, + FSL_XCVR_PHY_AI_CTRL_AI_RESETN); + if (ret < 0) { + dev_err(dev, "Error while setting IER0: %d\n", ret); + return ret; + } + + /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, + FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); return 0; } @@ -716,7 +769,8 @@ static const struct snd_soc_pcm_stream playback = { .rate_min = 32000, .rate_max = 1536000, .rates = SNDRV_PCM_RATE_KNOT, - .formats = FSL_XCVR_FORMATS, + .formats = SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, }; static const struct snd_soc_pcm_stream capture = { @@ -726,7 +780,7 @@ static const struct snd_soc_pcm_stream capture = { .rate_min = 32000, .rate_max = 1536000, .rates = SNDRV_PCM_RATE_KNOT, - .formats = FSL_XCVR_FORMATS, + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, }; static struct snd_soc_dai_driver fsl_xcvr_dai = { @@ -1198,14 +1252,6 @@ static int fsl_xcvr_runtime_resume(struct device *dev) return ret; } - /* Release M0+ reset */ - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, - FSL_XCVR_EXT_CTRL_CORE_RESET, 0); - if (ret < 0) { - dev_err(dev, "Failed to release M0+ core: %d\n", ret); - return ret; - } - return 0; } #endif /* CONFIG_PM*/ -- cgit v1.2.3