[alsa-devel] [PATCH v2 0/6] ] ASoC: atmel: extend SSC support
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
This series improves support for various configurations using SSC module as implemented in Atmel SAMA5Dx SoCs. Patches are:
1. enable SSC in Kconfig for audio-graph-card support 2. DRY mode setting code 3. implement left-justified data mode 4-6. enable shared FSYNC source for slave mode
Patches against tiwai/sound/for-next tree. You can also pull from https://rere.qmqm.pl/git/linux branch: atmel-ssc
Michał Mirosław (6): ASoC: atmel: enable SOC_SSC_PDC and SOC_SSC_DMA in Kconfig ASoC: atmel_ssc_dai: rework DAI format configuration ASoC: atmel_ssc_dai: implement left-justified data mode dt-bindings: misc: atmel-ssc: LRCLK from TF/RF pin option misc: atmel-ssc: get LRCLK pin selection from DT ASoC: atmel_ssc_dai: Enable shared FSYNC source in frame-slave mode
.../devicetree/bindings/misc/atmel-ssc.txt | 5 + drivers/misc/atmel-ssc.c | 9 + include/linux/atmel-ssc.h | 2 + sound/soc/atmel/Kconfig | 30 +- sound/soc/atmel/atmel_ssc_dai.c | 305 ++++++------------ 5 files changed, 137 insertions(+), 214 deletions(-)
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
Allow SSC to be used on platforms described using audio-graph-card in Device Tree.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
--- v2: extended to PDC mode reworked and fixed Kconfig option dependencies
--- sound/soc/atmel/Kconfig | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 06c1d5ce642c..f118c229ed82 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -12,25 +12,31 @@ if SND_ATMEL_SOC config SND_ATMEL_SOC_PDC tristate depends on HAS_DMA - default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_PDC - tristate
config SND_ATMEL_SOC_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM - default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_DMA - tristate
config SND_ATMEL_SOC_SSC tristate - default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y - default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m + +config SND_ATMEL_SOC_SSC_PDC + tristate "SoC PCM DAI support for AT91 SSC controller using PDC" + depends on ATMEL_SSC + select SND_ATMEL_SOC_PDC + select SND_ATMEL_SOC_SSC + help + Say Y or M if you want to add support for Atmel SSC interface + in PDC mode configured using audio-graph-card in device-tree. + +config SND_ATMEL_SOC_SSC_DMA + tristate "SoC PCM DAI support for AT91 SSC controller using DMA" + depends on ATMEL_SSC + select SND_ATMEL_SOC_DMA + select SND_ATMEL_SOC_SSC + help + Say Y or M if you want to add support for Atmel SSC interface + in DMA mode configured using audio-graph-card in device-tree.
config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
![](https://secure.gravatar.com/avatar/d44283e3c2b00ae6f9ad4ec22da61e00.jpg?s=120&d=mm&r=g)
On 24.08.2019 23:26, Michał Mirosław wrote:
Allow SSC to be used on platforms described using audio-graph-card in Device Tree.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
Reviewed-by: Codrin Ciubotariu codrin.ciubotariu@microchip.com
Thanks!
Best regards, Codrin
v2: extended to PDC mode reworked and fixed Kconfig option dependencies
sound/soc/atmel/Kconfig | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 06c1d5ce642c..f118c229ed82 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -12,25 +12,31 @@ if SND_ATMEL_SOC config SND_ATMEL_SOC_PDC tristate depends on HAS_DMA
- default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m
- default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y)
-config SND_ATMEL_SOC_SSC_PDC
tristate
config SND_ATMEL_SOC_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM
default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m
default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y)
-config SND_ATMEL_SOC_SSC_DMA
tristate
config SND_ATMEL_SOC_SSC tristate
default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y
default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m
+config SND_ATMEL_SOC_SSC_PDC
- tristate "SoC PCM DAI support for AT91 SSC controller using PDC"
- depends on ATMEL_SSC
- select SND_ATMEL_SOC_PDC
- select SND_ATMEL_SOC_SSC
- help
Say Y or M if you want to add support for Atmel SSC interface
in PDC mode configured using audio-graph-card in device-tree.
+config SND_ATMEL_SOC_SSC_DMA
tristate "SoC PCM DAI support for AT91 SSC controller using DMA"
depends on ATMEL_SSC
select SND_ATMEL_SOC_DMA
select SND_ATMEL_SOC_SSC
help
Say Y or M if you want to add support for Atmel SSC interface
in DMA mode configured using audio-graph-card in device-tree.
config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
![](https://secure.gravatar.com/avatar/e9b70778b7af3b79dc1bf62dc64f6685.jpg?s=120&d=mm&r=g)
On 24/08/2019 22:26:52+0200, Michał Mirosław wrote:
Allow SSC to be used on platforms described using audio-graph-card in Device Tree.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
Acked-by: Alexandre Belloni alexandre.belloni@bootlin.com
v2: extended to PDC mode reworked and fixed Kconfig option dependencies
sound/soc/atmel/Kconfig | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 06c1d5ce642c..f118c229ed82 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -12,25 +12,31 @@ if SND_ATMEL_SOC config SND_ATMEL_SOC_PDC tristate depends on HAS_DMA
- default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m
- default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y)
-config SND_ATMEL_SOC_SSC_PDC
- tristate
config SND_ATMEL_SOC_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM
- default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m
- default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y)
-config SND_ATMEL_SOC_SSC_DMA
- tristate
config SND_ATMEL_SOC_SSC tristate
- default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y
- default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m
+config SND_ATMEL_SOC_SSC_PDC
- tristate "SoC PCM DAI support for AT91 SSC controller using PDC"
- depends on ATMEL_SSC
- select SND_ATMEL_SOC_PDC
- select SND_ATMEL_SOC_SSC
- help
Say Y or M if you want to add support for Atmel SSC interface
in PDC mode configured using audio-graph-card in device-tree.
+config SND_ATMEL_SOC_SSC_DMA
- tristate "SoC PCM DAI support for AT91 SSC controller using DMA"
- depends on ATMEL_SSC
- select SND_ATMEL_SOC_DMA
- select SND_ATMEL_SOC_SSC
- help
Say Y or M if you want to add support for Atmel SSC interface
in DMA mode configured using audio-graph-card in device-tree.
config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" -- 2.20.1
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
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
--- v2: added note about extended modes' status incorporated common FS (LRCLK) configuration
--- sound/soc/atmel/atmel_ssc_dai.c | 286 +++++++++----------------------- 1 file changed, 80 insertions(+), 206 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,226 +558,36 @@ 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: - /* - * 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 = (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); + fslen_ext = (bits - 1) / 16; + fslen = (bits - 1) % 16;
- 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; - - 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; - } - - 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; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A 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. - */ - 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); + switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- 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)); + case SND_SOC_DAIFMT_I2S: + fs_osync = SSC_FSOS_NEGATIVE; + fs_edge = SSC_START_FALLING_RF;
- 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); + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 1);
- 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;
- case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_DSP_A: /* - * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. + * DSP/PCM Mode A format * * 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); + fs_osync = SSC_FSOS_POSITIVE; + fs_edge = SSC_START_RISING_RF; + fslen = fslen_ext = 0;
- 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)); + rcmr = SSC_BF(RCMR_STTDLY, 1); + tcmr = SSC_BF(TCMR_STTDLY, 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;
default: @@ -785,6 +595,70 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->daifmt); return -EINVAL; } + + if (!atmel_ssc_cfs(ssc_p)) { + fslen = fslen_ext = 0; + rcmr_period = tcmr_period = 0; + fs_osync = SSC_FSOS_NONE; + } + + rcmr |= SSC_BF(RCMR_START, fs_edge); + tcmr |= SSC_BF(TCMR_START, fs_edge); + + if (atmel_ssc_cbs(ssc_p)) { + /* + * 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_CKS, SSC_CKS_DIV) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE); + + 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); + + 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);
![](https://secure.gravatar.com/avatar/d44283e3c2b00ae6f9ad4ec22da61e00.jpg?s=120&d=mm&r=g)
On 24.08.2019 23:26, Michał Mirosław wrote:
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.)
The only mode added (and not tested) is for SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFS. I would mention it explicitly, instead of something generic. Also, SND_SOC_DAIFMT_CBM_CFS is not supported for any format, please see atmel_ssc_hw_rule_rate().
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
v2: added note about extended modes' status incorporated common FS (LRCLK) configuration
sound/soc/atmel/atmel_ssc_dai.c | 286 +++++++++----------------------- 1 file changed, 80 insertions(+), 206 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,226 +558,36 @@ 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:
/*
* 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 = (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);
- fslen_ext = (bits - 1) / 16;
- fslen = (bits - 1) % 16;
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;
- 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;
}
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;
- case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
/*
* DSP/PCM Mode A 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.
*/
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);
- switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
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));
- case SND_SOC_DAIFMT_I2S:
fs_osync = SSC_FSOS_NEGATIVE;
fs_edge = SSC_START_FALLING_RF;
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);
rcmr = SSC_BF(RCMR_STTDLY, 1);
tcmr = SSC_BF(TCMR_STTDLY, 1);
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;
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
- case SND_SOC_DAIFMT_DSP_A: /*
* DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
* DSP/PCM Mode A format
*/
- 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);
fs_osync = SSC_FSOS_POSITIVE;
fs_edge = SSC_START_RISING_RF;
fslen = fslen_ext = 0;
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));
rcmr = SSC_BF(RCMR_STTDLY, 1);
tcmr = SSC_BF(TCMR_STTDLY, 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;
default:
@@ -785,6 +595,70 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, ssc_p->daifmt); return -EINVAL; }
- if (!atmel_ssc_cfs(ssc_p)) {
fslen = fslen_ext = 0;
rcmr_period = tcmr_period = 0;
fs_osync = SSC_FSOS_NONE;
- }
- rcmr |= SSC_BF(RCMR_START, fs_edge);
- tcmr |= SSC_BF(TCMR_START, fs_edge);
Why not move these below in the code, where all the other bits of these two registers are set?
- if (atmel_ssc_cbs(ssc_p)) {
/*
* 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_CKS, SSC_CKS_DIV)
| SSC_BF(RCMR_CKO, SSC_CKO_NONE);
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);
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);
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
Enable support for left-justified data mode for SSC-codec link.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
--- v2: rebased
--- sound/soc/atmel/atmel_ssc_dai.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 7dc6ec9b8c7a..48e9eef34c0f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -564,6 +564,15 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J: + fs_osync = SSC_FSOS_POSITIVE; + fs_edge = SSC_START_RISING_RF; + + rcmr = SSC_BF(RCMR_STTDLY, 0); + tcmr = SSC_BF(TCMR_STTDLY, 0); + + break; + case SND_SOC_DAIFMT_I2S: fs_osync = SSC_FSOS_NEGATIVE; fs_edge = SSC_START_FALLING_RF;
![](https://secure.gravatar.com/avatar/d44283e3c2b00ae6f9ad4ec22da61e00.jpg?s=120&d=mm&r=g)
Enable support for left-justified data mode for SSC-codec link.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
v2: rebased
I noticed you also added a description and you removed two comments from v1. Please include all the changes in the changelog. I already added my 'Reviewed-by' in v1, but since there are some more changes from the previous version:
Reviewed-by: Codrin Ciubotariu codrin.ciubotariu@microchip.com
Thanks and best regards, Codrin
sound/soc/atmel/atmel_ssc_dai.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 7dc6ec9b8c7a..48e9eef34c0f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -564,6 +564,15 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
switch (ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_LEFT_J:
fs_osync = SSC_FSOS_POSITIVE;
fs_edge = SSC_START_RISING_RF;
rcmr = SSC_BF(RCMR_STTDLY, 0);
tcmr = SSC_BF(TCMR_STTDLY, 0);
break;
- case SND_SOC_DAIFMT_I2S: fs_osync = SSC_FSOS_NEGATIVE; fs_edge = SSC_START_FALLING_RF;
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
Add single-pin LRCLK source options for Atmel SSC module.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
--- v2: split from implementation patch
--- Documentation/devicetree/bindings/misc/atmel-ssc.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt index f9fb412642fe..c98e96dbec3a 100644 --- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -24,6 +24,11 @@ Optional properties: this parameter to choose where the clock from. - By default the clock is from TK pin, if the clock from RK pin, this property is needed. + - atmel,lrclk-from-tf-pin: bool property. + - atmel,lrclk-from-rf-pin: bool property. + - SSC in slave mode gets LRCLK from RF for receive and TF for transmit + data direction. This property makes both use single TF (or RF) pin + as LRCLK. At most one can be present. - #sound-dai-cells: Should contain <0>. - This property makes the SSC into an automatically registered DAI.
![](https://secure.gravatar.com/avatar/ee1e7f40e65828eb76184367a6353704.jpg?s=120&d=mm&r=g)
On Sat, Aug 24, 2019 at 10:26:55PM +0200, Michał Mirosław wrote:
Add single-pin LRCLK source options for Atmel SSC module.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
v2: split from implementation patch
Documentation/devicetree/bindings/misc/atmel-ssc.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt index f9fb412642fe..c98e96dbec3a 100644 --- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -24,6 +24,11 @@ Optional properties: this parameter to choose where the clock from. - By default the clock is from TK pin, if the clock from RK pin, this property is needed.
- atmel,lrclk-from-tf-pin: bool property.
- atmel,lrclk-from-rf-pin: bool property.
- SSC in slave mode gets LRCLK from RF for receive and TF for transmit
data direction. This property makes both use single TF (or RF) pin
as LRCLK. At most one can be present.
A single property taking 1 of possible 2 values would prevent the error of more than 1 property present.
- #sound-dai-cells: Should contain <0>.
- This property makes the SSC into an automatically registered DAI.
-- 2.20.1
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
On Tue, Aug 27, 2019 at 05:37:16PM -0500, Rob Herring wrote:
On Sat, Aug 24, 2019 at 10:26:55PM +0200, Michał Mirosław wrote:
Add single-pin LRCLK source options for Atmel SSC module.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
v2: split from implementation patch
Documentation/devicetree/bindings/misc/atmel-ssc.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt index f9fb412642fe..c98e96dbec3a 100644 --- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -24,6 +24,11 @@ Optional properties: this parameter to choose where the clock from. - By default the clock is from TK pin, if the clock from RK pin, this property is needed.
- atmel,lrclk-from-tf-pin: bool property.
- atmel,lrclk-from-rf-pin: bool property.
- SSC in slave mode gets LRCLK from RF for receive and TF for transmit
data direction. This property makes both use single TF (or RF) pin
as LRCLK. At most one can be present.
A single property taking 1 of possible 2 values would prevent the error of more than 1 property present.
It still would need a validation check in the code, though: you could put wrong value then. It seems more consistent with the existing parameters to have two bool properties.
Best Regards, Michał Mirosław
![](https://secure.gravatar.com/avatar/ee1e7f40e65828eb76184367a6353704.jpg?s=120&d=mm&r=g)
On Wed, Aug 28, 2019 at 8:03 AM Michał Mirosław mirq-linux@rere.qmqm.pl wrote:
On Tue, Aug 27, 2019 at 05:37:16PM -0500, Rob Herring wrote:
On Sat, Aug 24, 2019 at 10:26:55PM +0200, Michał Mirosław wrote:
Add single-pin LRCLK source options for Atmel SSC module.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
v2: split from implementation patch
Documentation/devicetree/bindings/misc/atmel-ssc.txt | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt index f9fb412642fe..c98e96dbec3a 100644 --- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -24,6 +24,11 @@ Optional properties: this parameter to choose where the clock from. - By default the clock is from TK pin, if the clock from RK pin, this property is needed.
- atmel,lrclk-from-tf-pin: bool property.
- atmel,lrclk-from-rf-pin: bool property.
- SSC in slave mode gets LRCLK from RF for receive and TF for transmit
data direction. This property makes both use single TF (or RF) pin
as LRCLK. At most one can be present.
A single property taking 1 of possible 2 values would prevent the error of more than 1 property present.
It still would need a validation check in the code, though: you could put wrong value then. It seems more consistent with the existing parameters to have two bool properties.
It was validation using schema that I was thinking about. Expressing a possible set of values for a property is easier than inter-property constraints.
But if you really prefer as-is:
Reviewed-by: Rob Herring robh@kernel.org
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
Store LRCLK pin selection for use by ASoC DAI driver.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
--- v2: split from ASoC implementation
--- drivers/misc/atmel-ssc.c | 9 +++++++++ include/linux/atmel-ssc.h | 2 ++ 2 files changed, 11 insertions(+)
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index ab4144ea1f11..1322e29bc37a 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -210,6 +210,15 @@ static int ssc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; ssc->clk_from_rk_pin = of_property_read_bool(np, "atmel,clk-from-rk-pin"); + ssc->lrclk_from_tf_pin = + of_property_read_bool(np, "atmel,lrclk-from-tf-pin"); + ssc->lrclk_from_rf_pin = + of_property_read_bool(np, "atmel,lrclk-from-rf-pin"); + + if (ssc->lrclk_from_tf_pin && ssc->lrclk_from_rf_pin) { + dev_err(&pdev->dev, "both LRCLK from RK/TK options found in DT node"); + return -EINVAL; + } }
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h index 6091d2abc1eb..fbe1c2ffaa81 100644 --- a/include/linux/atmel-ssc.h +++ b/include/linux/atmel-ssc.h @@ -21,6 +21,8 @@ struct ssc_device { int user; int irq; bool clk_from_rk_pin; + bool lrclk_from_tf_pin; + bool lrclk_from_rf_pin; bool sound_dai; };
![](https://secure.gravatar.com/avatar/d44283e3c2b00ae6f9ad4ec22da61e00.jpg?s=120&d=mm&r=g)
On 24.08.2019 23:26, Michał Mirosław wrote:
Store LRCLK pin selection for use by ASoC DAI driver.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
Reviewed-by: Codrin Ciubotariu codrin.ciubotariu@microchip.com
Thanks and best regards, Codrin
v2: split from ASoC implementation
drivers/misc/atmel-ssc.c | 9 +++++++++ include/linux/atmel-ssc.h | 2 ++ 2 files changed, 11 insertions(+)
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index ab4144ea1f11..1322e29bc37a 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -210,6 +210,15 @@ static int ssc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; ssc->clk_from_rk_pin = of_property_read_bool(np, "atmel,clk-from-rk-pin");
ssc->lrclk_from_tf_pin =
of_property_read_bool(np, "atmel,lrclk-from-tf-pin");
ssc->lrclk_from_rf_pin =
of_property_read_bool(np, "atmel,lrclk-from-rf-pin");
if (ssc->lrclk_from_tf_pin && ssc->lrclk_from_rf_pin) {
dev_err(&pdev->dev, "both LRCLK from RK/TK options found in DT node");
return -EINVAL;
}
}
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h index 6091d2abc1eb..fbe1c2ffaa81 100644 --- a/include/linux/atmel-ssc.h +++ b/include/linux/atmel-ssc.h @@ -21,6 +21,8 @@ struct ssc_device { int user; int irq; bool clk_from_rk_pin;
- bool lrclk_from_tf_pin;
- bool lrclk_from_rf_pin; bool sound_dai; };
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
SSC driver allows only synchronous TX and RX. In slave mode for BCLK it uses only one of TK or RK pin, but for LRCLK it configured separate inputs from TF and RF pins. Allow configuration with common FS signal.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
--- v2: use alternate DT binding split DT and drivers/misc changes
--- sound/soc/atmel/atmel_ssc_dai.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 48e9eef34c0f..035d4da58f2b 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -605,14 +605,32 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, return -EINVAL; }
- if (!atmel_ssc_cfs(ssc_p)) { + if (atmel_ssc_cfs(ssc_p)) { + /* + * SSC provides LRCLK + * + * Both TF and RF are generated, so use them directly. + */ + rcmr |= SSC_BF(RCMR_START, fs_edge); + tcmr |= SSC_BF(TCMR_START, fs_edge); + } else { fslen = fslen_ext = 0; rcmr_period = tcmr_period = 0; fs_osync = SSC_FSOS_NONE; - }
- rcmr |= SSC_BF(RCMR_START, fs_edge); - tcmr |= SSC_BF(TCMR_START, fs_edge); + if (ssc->lrclk_from_tf_pin) { + rcmr |= SSC_BF(RCMR_START, SSC_START_TX_RX); + tcmr |= SSC_BF(TCMR_START, fs_edge); + } else if (ssc->lrclk_from_rf_pin) { + /* assume RF is to be used when RK is used as BCLK input */ + /* Note: won't work correctly on SAMA5D2 due to errata */ + rcmr |= SSC_BF(RCMR_START, fs_edge); + tcmr |= SSC_BF(TCMR_START, SSC_START_TX_RX); + } else { + rcmr |= SSC_BF(RCMR_START, fs_edge); + tcmr |= SSC_BF(TCMR_START, fs_edge); + } + }
if (atmel_ssc_cbs(ssc_p)) { /*
![](https://secure.gravatar.com/avatar/d44283e3c2b00ae6f9ad4ec22da61e00.jpg?s=120&d=mm&r=g)
On 24.08.2019 23:26, Michał Mirosław wrote:
SSC driver allows only synchronous TX and RX. In slave mode for BCLK it uses only one of TK or RK pin, but for LRCLK it configured separate inputs from TF and RF pins. Allow configuration with common FS signal.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
v2: use alternate DT binding split DT and drivers/misc changes
sound/soc/atmel/atmel_ssc_dai.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 48e9eef34c0f..035d4da58f2b 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -605,14 +605,32 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, return -EINVAL; }
- if (!atmel_ssc_cfs(ssc_p)) {
- if (atmel_ssc_cfs(ssc_p)) {
/*
* SSC provides LRCLK
*
* Both TF and RF are generated, so use them directly.
*/
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, fs_edge);
Hmm, how would this work if capture and playback start/run at the same time?
- } else { fslen = fslen_ext = 0; rcmr_period = tcmr_period = 0; fs_osync = SSC_FSOS_NONE;
}
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, fs_edge);
if (ssc->lrclk_from_tf_pin) {
rcmr |= SSC_BF(RCMR_START, SSC_START_TX_RX);
tcmr |= SSC_BF(TCMR_START, fs_edge);
} else if (ssc->lrclk_from_rf_pin) {
/* assume RF is to be used when RK is used as BCLK input */
This comment is not longer true...
/* Note: won't work correctly on SAMA5D2 due to errata */
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, SSC_START_TX_RX);
} else {
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, fs_edge);
}
}
if (atmel_ssc_cbs(ssc_p)) { /*
Thanks and best regards, Codrin
![](https://secure.gravatar.com/avatar/32b3f613f9e074afffbd0c43380d11cc.jpg?s=120&d=mm&r=g)
On Mon, Aug 26, 2019 at 03:05:06PM +0000, Codrin.Ciubotariu@microchip.com wrote:
On 24.08.2019 23:26, Michał Mirosław wrote:
SSC driver allows only synchronous TX and RX. In slave mode for BCLK it uses only one of TK or RK pin, but for LRCLK it configured separate inputs from TF and RF pins. Allow configuration with common FS signal.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl
v2: use alternate DT binding split DT and drivers/misc changes
sound/soc/atmel/atmel_ssc_dai.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 48e9eef34c0f..035d4da58f2b 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -605,14 +605,32 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, return -EINVAL; }
- if (!atmel_ssc_cfs(ssc_p)) {
- if (atmel_ssc_cfs(ssc_p)) {
/*
* SSC provides LRCLK
*
* Both TF and RF are generated, so use them directly.
*/
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, fs_edge);
Hmm, how would this work if capture and playback start/run at the same time?
Same as it did before this patch: as there is only one bi-directional link between SSC and codec, whichever stream starts first defines the rate.
- } else { fslen = fslen_ext = 0; rcmr_period = tcmr_period = 0; fs_osync = SSC_FSOS_NONE;
}
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, fs_edge);
if (ssc->lrclk_from_tf_pin) {
rcmr |= SSC_BF(RCMR_START, SSC_START_TX_RX);
tcmr |= SSC_BF(TCMR_START, fs_edge);
} else if (ssc->lrclk_from_rf_pin) {
/* assume RF is to be used when RK is used as BCLK input */
This comment is not longer true...
Removed for next version.
/* Note: won't work correctly on SAMA5D2 due to errata */
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, SSC_START_TX_RX);
} else {
rcmr |= SSC_BF(RCMR_START, fs_edge);
tcmr |= SSC_BF(TCMR_START, fs_edge);
}
}
if (atmel_ssc_cbs(ssc_p)) { /*
Thanks and best regards, Codrin
Best Regards, Michał Mirosław
participants (5)
-
Alexandre Belloni
-
Codrin.Ciubotariu@microchip.com
-
Michał Mirosław
-
mirq-linux@rere.qmqm.pl
-
Rob Herring