ASoC: atmel_ssc_dai: rework DAI format configuration
authorMichał Mirosław <mirq-linux@rere.qmqm.pl>
Sat, 24 Aug 2019 20:26:53 +0000 (22:26 +0200)
committerMark Brown <broonie@kernel.org>
Tue, 27 Aug 2019 19:40:43 +0000 (20:40 +0100)
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>
sound/soc/atmel/atmel_ssc_dai.c

index 6f89483ac88c71d2f6440f6cc87d14792c6e4c29..7dc6ec9b8c7a8e8f162ddb1b335575e13e16548f 100644 (file)
@@ -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);