diff options
author | Michał Mirosław <mirq-linux@rere.qmqm.pl> | 2019-08-24 23:26:53 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-08-27 22:40:43 +0300 |
commit | db8e3e2091c3ccc4e1dde0f78b3111301cf129e9 (patch) | |
tree | a4b7f564ac00ba36aea62338cd759847cf71104a /sound/soc/atmel/atmel_ssc_dai.c | |
parent | 18291410557fb860706d1889505cc15d6e31d790 (diff) | |
download | linux-db8e3e2091c3ccc4e1dde0f78b3111301cf129e9.tar.xz |
ASoC: atmel_ssc_dai: rework DAI format configuration
Rework DAI format calculation in preparation for adding more formats
later. As a side-effect this enables all CBM/CBS x CFM/CFS combinations
for supported formats. (Note: the additional modes are not tested.)
Note: this changes FSEDGE to POSITIVE for I2S CBM_CFS mode as the TXSYN
interrupt is not used anyway.
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Link: https://lore.kernel.org/r/f5949b0326fdcdca072f3ed03f77de9e207631cd.1566677788.git.mirq-linux@rere.qmqm.pl
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/atmel/atmel_ssc_dai.c')
-rw-r--r-- | sound/soc/atmel/atmel_ssc_dai.c | 288 |
1 files changed, 81 insertions, 207 deletions
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 6f89483ac88c..7dc6ec9b8c7a 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -471,7 +471,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; int ret; - int fslen, fslen_ext; + int fslen, fslen_ext, fs_osync, fs_edge; u32 cmr_div; u32 tcmr_period; u32 rcmr_period; @@ -558,233 +558,107 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, /* * Compute SSC register settings. */ - switch (ssc_p->daifmt - & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + fslen_ext = (bits - 1) / 16; + fslen = (bits - 1) % 16; + + switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + + case SND_SOC_DAIFMT_I2S: + fs_osync = SSC_FSOS_NEGATIVE; + fs_edge = SSC_START_FALLING_RF; + + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 1); + + break; + + case SND_SOC_DAIFMT_DSP_A: /* - * I2S format, SSC provides BCLK and LRC clocks. + * DSP/PCM Mode A format * - * The SSC transmit and receive clocks are generated - * from the MCK divider, and the BCLK signal - * is output on the SSC TK line. + * Data is transferred on first BCLK after LRC pulse rising + * edge.If stereo, the right channel data is contiguous with + * the left channel data. */ + fs_osync = SSC_FSOS_POSITIVE; + fs_edge = SSC_START_RISING_RF; + fslen = fslen_ext = 0; - if (bits > 16 && !ssc->pdata->has_fslen_ext) { - dev_err(dai->dev, - "sample size %d is too large for SSC device\n", - bits); - return -EINVAL; - } + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 1); - fslen_ext = (bits - 1) / 16; - fslen = (bits - 1) % 16; - - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, fslen) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, fslen) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); break; - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* I2S format, CODEC supplies BCLK and LRC clocks. */ - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, 0) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + default: + printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", + ssc_p->daifmt); + return -EINVAL; + } - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS: - /* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */ - if (bits > 16 && !ssc->pdata->has_fslen_ext) { - dev_err(dai->dev, - "sample size %d is too large for SSC device\n", - bits); - return -EINVAL; - } + if (!atmel_ssc_cfs(ssc_p)) { + fslen = fslen_ext = 0; + rcmr_period = tcmr_period = 0; + fs_osync = SSC_FSOS_NONE; + } - fslen_ext = (bits - 1) / 16; - fslen = (bits - 1) % 16; - - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, fslen) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) - | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, fslen) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + rcmr |= SSC_BF(RCMR_START, fs_edge); + tcmr |= SSC_BF(TCMR_START, fs_edge); - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + if (atmel_ssc_cbs(ssc_p)) { /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * SSC provides BCLK * * The SSC transmit and receive clocks are generated from the * MCK divider, and the BCLK signal is output * on the SSC TK line. */ - rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) - | SSC_BF(RCMR_STTDLY, 1) - | SSC_BF(RCMR_START, SSC_START_RISING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) - | SSC_BF(TCMR_STTDLY, 1) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + rcmr |= SSC_BF(RCMR_CKS, SSC_CKS_DIV) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE); - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - /* - * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. - * - * Data is transferred on first BCLK after LRC pulse rising - * edge.If stereo, the right channel data is contiguous with - * the left channel data. - */ - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_RISING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_PIN : SSC_CKS_CLOCK); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, (channels - 1)) - | SSC_BIT(RFMR_MSBF) - | SSC_BF(RFMR_LOOP, 0) - | SSC_BF(RFMR_DATLEN, (bits - 1)); - - tcmr = SSC_BF(TCMR_PERIOD, 0) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? - SSC_CKS_CLOCK : SSC_CKS_PIN); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(TFMR_FSLEN, 0) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; + tcmr |= SSC_BF(TCMR_CKS, SSC_CKS_DIV) + | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS); + } else { + rcmr |= SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_PIN : SSC_CKS_CLOCK) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE); - default: - printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", - ssc_p->daifmt); + tcmr |= SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_CLOCK : SSC_CKS_PIN) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE); + } + + rcmr |= SSC_BF(RCMR_PERIOD, rcmr_period) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING); + + tcmr |= SSC_BF(TCMR_PERIOD, tcmr_period) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING); + + rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, fs_osync) + | SSC_BF(RFMR_FSLEN, fslen) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext) + | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, fs_osync) + | SSC_BF(TFMR_FSLEN, fslen) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + + if (fslen_ext && !ssc->pdata->has_fslen_ext) { + dev_err(dai->dev, "sample size %d is too large for SSC device\n", + bits); return -EINVAL; } + pr_debug("atmel_ssc_hw_params: " "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); |