Commit db8e3e20 authored by Michał Mirosław's avatar Michał Mirosław Committed by Mark Brown

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: default avatarMichał Mirosław <mirq-linux@rere.qmqm.pl>
Link: https://lore.kernel.org/r/f5949b0326fdcdca072f3ed03f77de9e207631cd.1566677788.git.mirq-linux@rere.qmqm.plSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 18291410
...@@ -471,7 +471,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ...@@ -471,7 +471,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
int dir, channels, bits; int dir, channels, bits;
u32 tfmr, rfmr, tcmr, rcmr; u32 tfmr, rfmr, tcmr, rcmr;
int ret; int ret;
int fslen, fslen_ext; int fslen, fslen_ext, fs_osync, fs_edge;
u32 cmr_div; u32 cmr_div;
u32 tcmr_period; u32 tcmr_period;
u32 rcmr_period; u32 rcmr_period;
...@@ -558,233 +558,107 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ...@@ -558,233 +558,107 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
/* /*
* Compute SSC register settings. * 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:
/*
* I2S format, SSC provides BCLK and LRC clocks.
*
* The SSC transmit and receive clocks are generated
* from the MCK divider, and the BCLK signal
* is output on the SSC TK line.
*/
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;
}
fslen_ext = (bits - 1) / 16; fslen_ext = (bits - 1) / 16;
fslen = (bits - 1) % 16; fslen = (bits - 1) % 16;
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
| 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) case SND_SOC_DAIFMT_I2S:
| SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) fs_osync = SSC_FSOS_NEGATIVE;
| SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) fs_edge = SSC_START_FALLING_RF;
| 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) rcmr = SSC_BF(RCMR_STTDLY, 1);
| SSC_BF(TCMR_STTDLY, START_DELAY) tcmr = SSC_BF(TCMR_STTDLY, 1);
| 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; break;
case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_DSP_A:
/* I2S format, CODEC supplies BCLK and LRC clocks. */ /*
rcmr = SSC_BF(RCMR_PERIOD, 0) * DSP/PCM Mode A format
| SSC_BF(RCMR_STTDLY, START_DELAY) *
| SSC_BF(RCMR_START, SSC_START_FALLING_RF) * Data is transferred on first BCLK after LRC pulse rising
| SSC_BF(RCMR_CKI, SSC_CKI_RISING) * edge.If stereo, the right channel data is contiguous with
| SSC_BF(RCMR_CKO, SSC_CKO_NONE) * the left channel data.
| SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? */
SSC_CKS_PIN : SSC_CKS_CLOCK); fs_osync = SSC_FSOS_POSITIVE;
fs_edge = SSC_START_RISING_RF;
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) fslen = fslen_ext = 0;
| 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) rcmr = SSC_BF(RCMR_STTDLY, 1);
| SSC_BF(TCMR_STTDLY, START_DELAY) tcmr = SSC_BF(TCMR_STTDLY, 1);
| 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; break;
case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS: default:
/* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */ printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
if (bits > 16 && !ssc->pdata->has_fslen_ext) { ssc_p->daifmt);
dev_err(dai->dev,
"sample size %d is too large for SSC device\n",
bits);
return -EINVAL; return -EINVAL;
} }
fslen_ext = (bits - 1) / 16; if (!atmel_ssc_cfs(ssc_p)) {
fslen = (bits - 1) % 16; fslen = fslen_ext = 0;
rcmr_period = tcmr_period = 0;
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) fs_osync = SSC_FSOS_NONE;
| 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) rcmr |= SSC_BF(RCMR_START, fs_edge);
| SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE) tcmr |= SSC_BF(TCMR_START, fs_edge);
| 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_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 * The SSC transmit and receive clocks are generated from the
* MCK divider, and the BCLK signal is output * MCK divider, and the BCLK signal is output
* on the SSC TK line. * on the SSC TK line.
*/ */
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) rcmr |= SSC_BF(RCMR_CKS, SSC_CKS_DIV)
| SSC_BF(RCMR_STTDLY, 1) | SSC_BF(RCMR_CKO, SSC_CKO_NONE);
| 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) tcmr |= SSC_BF(TCMR_CKS, SSC_CKS_DIV)
| SSC_BF(TCMR_STTDLY, 1) | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS);
| SSC_BF(TCMR_START, SSC_START_RISING_RF) } else {
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING) rcmr |= SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) SSC_CKS_PIN : SSC_CKS_CLOCK)
| SSC_BF(TCMR_CKS, SSC_CKS_DIV); | SSC_BF(RCMR_CKO, SSC_CKO_NONE);
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) tcmr |= SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
| SSC_BF(TFMR_FSDEN, 0) SSC_CKS_CLOCK : SSC_CKS_PIN)
| SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | SSC_BF(TCMR_CKO, SSC_CKO_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;
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: rcmr |= SSC_BF(RCMR_PERIOD, rcmr_period)
/* | SSC_BF(RCMR_CKI, SSC_CKI_RISING);
* DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
* tcmr |= SSC_BF(TCMR_PERIOD, tcmr_period)
* Data is transferred on first BCLK after LRC pulse rising | SSC_BF(TCMR_CKI, SSC_CKI_FALLING);
* edge.If stereo, the right channel data is contiguous with
* the left channel data. rfmr = SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
*/ | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
rcmr = SSC_BF(RCMR_PERIOD, 0) | SSC_BF(RFMR_FSOS, fs_osync)
| SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RFMR_FSLEN, fslen)
| 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_BF(RFMR_DATNB, (channels - 1))
| SSC_BIT(RFMR_MSBF) | SSC_BIT(RFMR_MSBF)
| SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_LOOP, 0)
| SSC_BF(RFMR_DATLEN, (bits - 1)); | SSC_BF(RFMR_DATLEN, (bits - 1));
tcmr = SSC_BF(TCMR_PERIOD, 0) tfmr = SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
| SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
| 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_FSDEN, 0)
| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | SSC_BF(TFMR_FSOS, fs_osync)
| SSC_BF(TFMR_FSLEN, 0) | SSC_BF(TFMR_FSLEN, fslen)
| SSC_BF(TFMR_DATNB, (channels - 1)) | SSC_BF(TFMR_DATNB, (channels - 1))
| SSC_BIT(TFMR_MSBF) | SSC_BIT(TFMR_MSBF)
| SSC_BF(TFMR_DATDEF, 0) | SSC_BF(TFMR_DATDEF, 0)
| SSC_BF(TFMR_DATLEN, (bits - 1)); | SSC_BF(TFMR_DATLEN, (bits - 1));
break;
default: if (fslen_ext && !ssc->pdata->has_fslen_ext) {
printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", dev_err(dai->dev, "sample size %d is too large for SSC device\n",
ssc_p->daifmt); bits);
return -EINVAL; return -EINVAL;
} }
pr_debug("atmel_ssc_hw_params: " pr_debug("atmel_ssc_hw_params: "
"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
rcmr, rfmr, tcmr, tfmr); rcmr, rfmr, tcmr, tfmr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment