All of lore.kernel.org
 help / color / mirror / Atom feed
* [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
@ 2017-10-19 13:03 ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

This patch-set adds support of synchronization features for SAI interface.
It also adds minor fixes and improvements.

Olivier Moysan (7):
  ASoC: stm32: Add synchronization to SAI bindings
  ASoC: stm32: sai: Move static settings to DAI init
  ASoC: stm32: sai: Fix DMA burst size
  ASoC: stm32: sai: fix stop management in isr
  ASoC: stm32: sai: Remove spurious IRQs on stop
  ASoC: stm32: sai: Fix get reset controller
  ASoC: stm32: sai: Add synchronization support

 .../devicetree/bindings/sound/st,stm32-sai.txt     |  14 +-
 sound/soc/stm/stm32_sai.c                          | 162 ++++++++++++++++++++-
 sound/soc/stm/stm32_sai.h                          |  22 ++-
 sound/soc/stm/stm32_sai_sub.c                      | 156 +++++++++++++++++---
 4 files changed, 318 insertions(+), 36 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
@ 2017-10-19 13:03 ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

This patch-set adds support of synchronization features for SAI interface.
It also adds minor fixes and improvements.

Olivier Moysan (7):
  ASoC: stm32: Add synchronization to SAI bindings
  ASoC: stm32: sai: Move static settings to DAI init
  ASoC: stm32: sai: Fix DMA burst size
  ASoC: stm32: sai: fix stop management in isr
  ASoC: stm32: sai: Remove spurious IRQs on stop
  ASoC: stm32: sai: Fix get reset controller
  ASoC: stm32: sai: Add synchronization support

 .../devicetree/bindings/sound/st,stm32-sai.txt     |  14 +-
 sound/soc/stm/stm32_sai.c                          | 162 ++++++++++++++++++++-
 sound/soc/stm/stm32_sai.h                          |  22 ++-
 sound/soc/stm/stm32_sai_sub.c                      | 156 +++++++++++++++++---
 4 files changed, 318 insertions(+), 36 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
@ 2017-10-19 13:03 ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patch-set adds support of synchronization features for SAI interface.
It also adds minor fixes and improvements.

Olivier Moysan (7):
  ASoC: stm32: Add synchronization to SAI bindings
  ASoC: stm32: sai: Move static settings to DAI init
  ASoC: stm32: sai: Fix DMA burst size
  ASoC: stm32: sai: fix stop management in isr
  ASoC: stm32: sai: Remove spurious IRQs on stop
  ASoC: stm32: sai: Fix get reset controller
  ASoC: stm32: sai: Add synchronization support

 .../devicetree/bindings/sound/st,stm32-sai.txt     |  14 +-
 sound/soc/stm/stm32_sai.c                          | 162 ++++++++++++++++++++-
 sound/soc/stm/stm32_sai.h                          |  22 ++-
 sound/soc/stm/stm32_sai_sub.c                      | 156 +++++++++++++++++---
 4 files changed, 318 insertions(+), 36 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 1/7] ASoC: stm32: Add synchronization to SAI bindings
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:03   ` Olivier Moysan
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Add synchronization configuration to STM32 SAI bindings.
This patch also adds peripheral clock which is required
to access synchronization register.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index f1c5ae5..1f9cd70 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -10,13 +10,21 @@ Required properties:
   - reg: Base address and size of SAI common register set.
   - clocks: Must contain phandle and clock specifier pairs for each entry
 	in clock-names.
-  - clock-names: Must contain "x8k" and "x11k"
+  - clock-names: Must contain "pclk" "x8k" and "x11k"
+	"pclk": Clock which feeds the peripheral bus interface.
+	        Mandatory for "st,stm32h7-sai" compatible.
+	        Not used for "st,stm32f4-sai" compatible.
 	"x8k": SAI parent clock for sampling rates multiple of 8kHz.
 	"x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
   - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
 
 Optional properties:
   - resets: Reference to a reset controller asserting the SAI
+  - st,sync: specify synchronization mode.
+	By default SAI sub-block is in asynchronous mode.
+	This property sets SAI sub-block as slave of another SAI sub-block.
+	Must contain the phandle and index of the sai sub-block providing
+	the synchronization.
 
 SAI subnodes:
 Two subnodes corresponding to SAI sub-block instances A et B can be defined.
@@ -52,8 +60,8 @@ sai1: sai1@40015800 {
 	#size-cells = <1>;
 	ranges = <0 0x40015800 0x400>;
 	reg = <0x40015800 0x4>;
-	clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
-	clock-names = "x8k", "x11k";
+	clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
+	clock-names = "pclk", "x8k", "x11k";
 	interrupts = <87>;
 
 	sai1a: audio-controller@40015804 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 1/7] ASoC: stm32: Add synchronization to SAI bindings
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Add synchronization configuration to STM32 SAI bindings.
This patch also adds peripheral clock which is required
to access synchronization register.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index f1c5ae5..1f9cd70 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -10,13 +10,21 @@ Required properties:
   - reg: Base address and size of SAI common register set.
   - clocks: Must contain phandle and clock specifier pairs for each entry
 	in clock-names.
-  - clock-names: Must contain "x8k" and "x11k"
+  - clock-names: Must contain "pclk" "x8k" and "x11k"
+	"pclk": Clock which feeds the peripheral bus interface.
+	        Mandatory for "st,stm32h7-sai" compatible.
+	        Not used for "st,stm32f4-sai" compatible.
 	"x8k": SAI parent clock for sampling rates multiple of 8kHz.
 	"x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
   - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
 
 Optional properties:
   - resets: Reference to a reset controller asserting the SAI
+  - st,sync: specify synchronization mode.
+	By default SAI sub-block is in asynchronous mode.
+	This property sets SAI sub-block as slave of another SAI sub-block.
+	Must contain the phandle and index of the sai sub-block providing
+	the synchronization.
 
 SAI subnodes:
 Two subnodes corresponding to SAI sub-block instances A et B can be defined.
@@ -52,8 +60,8 @@ sai1: sai1@40015800 {
 	#size-cells = <1>;
 	ranges = <0 0x40015800 0x400>;
 	reg = <0x40015800 0x4>;
-	clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
-	clock-names = "x8k", "x11k";
+	clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
+	clock-names = "pclk", "x8k", "x11k";
 	interrupts = <87>;
 
 	sai1a: audio-controller@40015804 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 1/7] ASoC: stm32: Add synchronization to SAI bindings
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Add synchronization configuration to STM32 SAI bindings.
This patch also adds peripheral clock which is required
to access synchronization register.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index f1c5ae5..1f9cd70 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -10,13 +10,21 @@ Required properties:
   - reg: Base address and size of SAI common register set.
   - clocks: Must contain phandle and clock specifier pairs for each entry
 	in clock-names.
-  - clock-names: Must contain "x8k" and "x11k"
+  - clock-names: Must contain "pclk" "x8k" and "x11k"
+	"pclk": Clock which feeds the peripheral bus interface.
+	        Mandatory for "st,stm32h7-sai" compatible.
+	        Not used for "st,stm32f4-sai" compatible.
 	"x8k": SAI parent clock for sampling rates multiple of 8kHz.
 	"x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
   - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
 
 Optional properties:
   - resets: Reference to a reset controller asserting the SAI
+  - st,sync: specify synchronization mode.
+	By default SAI sub-block is in asynchronous mode.
+	This property sets SAI sub-block as slave of another SAI sub-block.
+	Must contain the phandle and index of the sai sub-block providing
+	the synchronization.
 
 SAI subnodes:
 Two subnodes corresponding to SAI sub-block instances A et B can be defined.
@@ -52,8 +60,8 @@ sai1: sai1 at 40015800 {
 	#size-cells = <1>;
 	ranges = <0 0x40015800 0x400>;
 	reg = <0x40015800 0x4>;
-	clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
-	clock-names = "x8k", "x11k";
+	clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
+	clock-names = "pclk", "x8k", "x11k";
 	interrupts = <87>;
 
 	sai1a: audio-controller at 40015804 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 2/7] ASoC: stm32: sai: Move static settings to DAI init
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:03   ` Olivier Moysan
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Audio interface direction and protocol settings does not change
at runtime. So, these settings are moved from hw_params
function to dai_probe and set_fmt.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 90d4396..fdc1891 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -304,12 +304,15 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
 static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
-	int cr1 = 0, frcr = 0;
-	int cr1_mask = 0, frcr_mask = 0;
+	int cr1, frcr = 0;
+	int cr1_mask, frcr_mask = 0;
 	int ret;
 
 	dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
 
+	cr1_mask = SAI_XCR1_PRTCFG_MASK;
+	cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	/* SCK active high for all protocols */
 	case SND_SOC_DAIFMT_I2S:
@@ -336,7 +339,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	cr1_mask |= SAI_XCR1_PRTCFG_MASK | SAI_XCR1_CKSTR;
+	cr1_mask |= SAI_XCR1_CKSTR;
 	frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF |
 		     SAI_XFRCR_FSDEF;
 
@@ -450,7 +453,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
 
 	/* Mode, data format and channel config */
-	cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+	cr1_mask = SAI_XCR1_DS_MASK;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S8:
 		cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8);
@@ -465,11 +468,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 		dev_err(cpu_dai->dev, "Data format not supported");
 		return -EINVAL;
 	}
-	cr1_mask = SAI_XCR1_DS_MASK | SAI_XCR1_PRTCFG_MASK;
-
-	cr1_mask |= SAI_XCR1_RX_TX;
-	if (STM_SAI_IS_CAPTURE(sai))
-		cr1 |= SAI_XCR1_RX_TX;
 
 	cr1_mask |= SAI_XCR1_MONO;
 	if ((sai->slots == 2) && (params_channels(params) == 1))
@@ -725,6 +723,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
 static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
 	struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+	int cr1 = 0, cr1_mask;
 
 	sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
 	sai->dma_params.maxburst = 1;
@@ -736,7 +735,11 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	else
 		snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
 
-	return 0;
+	cr1_mask = SAI_XCR1_RX_TX;
+	if (STM_SAI_IS_CAPTURE(sai))
+		cr1 |= SAI_XCR1_RX_TX;
+
+	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
 static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 2/7] ASoC: stm32: sai: Move static settings to DAI init
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Audio interface direction and protocol settings does not change
at runtime. So, these settings are moved from hw_params
function to dai_probe and set_fmt.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 90d4396..fdc1891 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -304,12 +304,15 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
 static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
-	int cr1 = 0, frcr = 0;
-	int cr1_mask = 0, frcr_mask = 0;
+	int cr1, frcr = 0;
+	int cr1_mask, frcr_mask = 0;
 	int ret;
 
 	dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
 
+	cr1_mask = SAI_XCR1_PRTCFG_MASK;
+	cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	/* SCK active high for all protocols */
 	case SND_SOC_DAIFMT_I2S:
@@ -336,7 +339,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	cr1_mask |= SAI_XCR1_PRTCFG_MASK | SAI_XCR1_CKSTR;
+	cr1_mask |= SAI_XCR1_CKSTR;
 	frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF |
 		     SAI_XFRCR_FSDEF;
 
@@ -450,7 +453,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
 
 	/* Mode, data format and channel config */
-	cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+	cr1_mask = SAI_XCR1_DS_MASK;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S8:
 		cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8);
@@ -465,11 +468,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 		dev_err(cpu_dai->dev, "Data format not supported");
 		return -EINVAL;
 	}
-	cr1_mask = SAI_XCR1_DS_MASK | SAI_XCR1_PRTCFG_MASK;
-
-	cr1_mask |= SAI_XCR1_RX_TX;
-	if (STM_SAI_IS_CAPTURE(sai))
-		cr1 |= SAI_XCR1_RX_TX;
 
 	cr1_mask |= SAI_XCR1_MONO;
 	if ((sai->slots == 2) && (params_channels(params) == 1))
@@ -725,6 +723,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
 static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
 	struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+	int cr1 = 0, cr1_mask;
 
 	sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
 	sai->dma_params.maxburst = 1;
@@ -736,7 +735,11 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	else
 		snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
 
-	return 0;
+	cr1_mask = SAI_XCR1_RX_TX;
+	if (STM_SAI_IS_CAPTURE(sai))
+		cr1 |= SAI_XCR1_RX_TX;
+
+	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
 static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 2/7] ASoC: stm32: sai: Move static settings to DAI init
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Audio interface direction and protocol settings does not change
at runtime. So, these settings are moved from hw_params
function to dai_probe and set_fmt.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 90d4396..fdc1891 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -304,12 +304,15 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
 static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
-	int cr1 = 0, frcr = 0;
-	int cr1_mask = 0, frcr_mask = 0;
+	int cr1, frcr = 0;
+	int cr1_mask, frcr_mask = 0;
 	int ret;
 
 	dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
 
+	cr1_mask = SAI_XCR1_PRTCFG_MASK;
+	cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	/* SCK active high for all protocols */
 	case SND_SOC_DAIFMT_I2S:
@@ -336,7 +339,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	cr1_mask |= SAI_XCR1_PRTCFG_MASK | SAI_XCR1_CKSTR;
+	cr1_mask |= SAI_XCR1_CKSTR;
 	frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF |
 		     SAI_XFRCR_FSDEF;
 
@@ -450,7 +453,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
 
 	/* Mode, data format and channel config */
-	cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+	cr1_mask = SAI_XCR1_DS_MASK;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S8:
 		cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8);
@@ -465,11 +468,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 		dev_err(cpu_dai->dev, "Data format not supported");
 		return -EINVAL;
 	}
-	cr1_mask = SAI_XCR1_DS_MASK | SAI_XCR1_PRTCFG_MASK;
-
-	cr1_mask |= SAI_XCR1_RX_TX;
-	if (STM_SAI_IS_CAPTURE(sai))
-		cr1 |= SAI_XCR1_RX_TX;
 
 	cr1_mask |= SAI_XCR1_MONO;
 	if ((sai->slots == 2) && (params_channels(params) == 1))
@@ -725,6 +723,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
 static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
 	struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+	int cr1 = 0, cr1_mask;
 
 	sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
 	sai->dma_params.maxburst = 1;
@@ -736,7 +735,11 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	else
 		snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
 
-	return 0;
+	cr1_mask = SAI_XCR1_RX_TX;
+	if (STM_SAI_IS_CAPTURE(sai))
+		cr1 |= SAI_XCR1_RX_TX;
+
+	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
 static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 3/7] ASoC: stm32: sai: Fix DMA burst size
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:03   ` Olivier Moysan
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Set best burst size tradeoff for 8, 16, 32 bits transfers.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fdc1891..2af397d 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -445,12 +445,16 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 {
 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
 	int cr1, cr1_mask, ret;
-	int fth = STM_SAI_FIFO_TH_HALF;
 
-	/* FIFO config */
+	/*
+	 * DMA bursts increment is set to 4 words.
+	 * SAI fifo threshold is set to half fifo, to keep enough space
+	 * for DMA incoming bursts.
+	 */
 	regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX,
 			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
-			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
+			   SAI_XCR2_FFLUSH |
+			   SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
 
 	/* Mode, data format and channel config */
 	cr1_mask = SAI_XCR1_DS_MASK;
@@ -479,10 +483,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 		return ret;
 	}
 
-	/* DMA config */
-	sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32);
-	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&sai->dma_params);
-
 	return 0;
 }
 
@@ -726,7 +726,12 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	int cr1 = 0, cr1_mask;
 
 	sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
-	sai->dma_params.maxburst = 1;
+	/*
+	 * DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice,
+	 * as it allows bytes, half-word and words transfers. (See DMA fifos
+	 * constraints).
+	 */
+	sai->dma_params.maxburst = 4;
 	/* Buswidth will be set by framework at runtime */
 	sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 3/7] ASoC: stm32: sai: Fix DMA burst size
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Set best burst size tradeoff for 8, 16, 32 bits transfers.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fdc1891..2af397d 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -445,12 +445,16 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 {
 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
 	int cr1, cr1_mask, ret;
-	int fth = STM_SAI_FIFO_TH_HALF;
 
-	/* FIFO config */
+	/*
+	 * DMA bursts increment is set to 4 words.
+	 * SAI fifo threshold is set to half fifo, to keep enough space
+	 * for DMA incoming bursts.
+	 */
 	regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX,
 			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
-			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
+			   SAI_XCR2_FFLUSH |
+			   SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
 
 	/* Mode, data format and channel config */
 	cr1_mask = SAI_XCR1_DS_MASK;
@@ -479,10 +483,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 		return ret;
 	}
 
-	/* DMA config */
-	sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32);
-	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&sai->dma_params);
-
 	return 0;
 }
 
@@ -726,7 +726,12 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	int cr1 = 0, cr1_mask;
 
 	sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
-	sai->dma_params.maxburst = 1;
+	/*
+	 * DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice,
+	 * as it allows bytes, half-word and words transfers. (See DMA fifos
+	 * constraints).
+	 */
+	sai->dma_params.maxburst = 4;
 	/* Buswidth will be set by framework at runtime */
 	sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 3/7] ASoC: stm32: sai: Fix DMA burst size
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Set best burst size tradeoff for 8, 16, 32 bits transfers.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fdc1891..2af397d 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -445,12 +445,16 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 {
 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
 	int cr1, cr1_mask, ret;
-	int fth = STM_SAI_FIFO_TH_HALF;
 
-	/* FIFO config */
+	/*
+	 * DMA bursts increment is set to 4 words.
+	 * SAI fifo threshold is set to half fifo, to keep enough space
+	 * for DMA incoming bursts.
+	 */
 	regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX,
 			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
-			   SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
+			   SAI_XCR2_FFLUSH |
+			   SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
 
 	/* Mode, data format and channel config */
 	cr1_mask = SAI_XCR1_DS_MASK;
@@ -479,10 +483,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
 		return ret;
 	}
 
-	/* DMA config */
-	sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32);
-	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&sai->dma_params);
-
 	return 0;
 }
 
@@ -726,7 +726,12 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	int cr1 = 0, cr1_mask;
 
 	sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
-	sai->dma_params.maxburst = 1;
+	/*
+	 * DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice,
+	 * as it allows bytes, half-word and words transfers. (See DMA fifos
+	 * constraints).
+	 */
+	sai->dma_params.maxburst = 4;
 	/* Buswidth will be set by framework at runtime */
 	sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:03   ` Olivier Moysan
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Add check on substream validity.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 2af397d..815ef10 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
 static irqreturn_t stm32_sai_isr(int irq, void *devid)
 {
 	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
-	struct snd_pcm_substream *substream = sai->substream;
 	struct platform_device *pdev = sai->pdev;
 	unsigned int sr, imr, flags;
 	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
 			   SAI_XCLRFR_MASK);
 
+	if (!sai->substream) {
+		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
+		return IRQ_NONE;
+	}
+
 	if (flags & SAI_XIMR_OVRUDRIE) {
 		dev_err(&pdev->dev, "IRQ %s\n",
 			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	}
 
 	if (status != SNDRV_PCM_STATE_RUNNING) {
-		snd_pcm_stream_lock(substream);
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		snd_pcm_stream_unlock(substream);
+		snd_pcm_stream_lock(sai->substream);
+		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock(sai->substream);
 	}
 
 	return IRQ_HANDLED;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Add check on substream validity.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 2af397d..815ef10 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
 static irqreturn_t stm32_sai_isr(int irq, void *devid)
 {
 	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
-	struct snd_pcm_substream *substream = sai->substream;
 	struct platform_device *pdev = sai->pdev;
 	unsigned int sr, imr, flags;
 	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
 			   SAI_XCLRFR_MASK);
 
+	if (!sai->substream) {
+		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
+		return IRQ_NONE;
+	}
+
 	if (flags & SAI_XIMR_OVRUDRIE) {
 		dev_err(&pdev->dev, "IRQ %s\n",
 			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	}
 
 	if (status != SNDRV_PCM_STATE_RUNNING) {
-		snd_pcm_stream_lock(substream);
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		snd_pcm_stream_unlock(substream);
+		snd_pcm_stream_lock(sai->substream);
+		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock(sai->substream);
 	}
 
 	return IRQ_HANDLED;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Add check on substream validity.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 2af397d..815ef10 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
 static irqreturn_t stm32_sai_isr(int irq, void *devid)
 {
 	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
-	struct snd_pcm_substream *substream = sai->substream;
 	struct platform_device *pdev = sai->pdev;
 	unsigned int sr, imr, flags;
 	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
 			   SAI_XCLRFR_MASK);
 
+	if (!sai->substream) {
+		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
+		return IRQ_NONE;
+	}
+
 	if (flags & SAI_XIMR_OVRUDRIE) {
 		dev_err(&pdev->dev, "IRQ %s\n",
 			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	}
 
 	if (status != SNDRV_PCM_STATE_RUNNING) {
-		snd_pcm_stream_lock(substream);
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		snd_pcm_stream_unlock(substream);
+		snd_pcm_stream_lock(sai->substream);
+		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock(sai->substream);
 	}
 
 	return IRQ_HANDLED;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 5/7] ASoC: stm32: sai: Remove spurious IRQs on stop
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:03   ` Olivier Moysan
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Clear IRQ mask on stream stop to avoid spurious IRQs.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 815ef10..fd7dc77 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -419,8 +419,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
 	}
 
 	/* Enable ITs */
-	regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
-			   SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
 
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
 			   SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
@@ -693,6 +691,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_STOP:
 		dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
 
+		regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+				   SAI_XIMR_MASK, 0);
+
 		regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 				   SAI_XCR1_SAIEN,
 				   (unsigned int)~SAI_XCR1_SAIEN);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 5/7] ASoC: stm32: sai: Remove spurious IRQs on stop
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Clear IRQ mask on stream stop to avoid spurious IRQs.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 815ef10..fd7dc77 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -419,8 +419,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
 	}
 
 	/* Enable ITs */
-	regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
-			   SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
 
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
 			   SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
@@ -693,6 +691,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_STOP:
 		dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
 
+		regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+				   SAI_XIMR_MASK, 0);
+
 		regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 				   SAI_XCR1_SAIEN,
 				   (unsigned int)~SAI_XCR1_SAIEN);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 5/7] ASoC: stm32: sai: Remove spurious IRQs on stop
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Clear IRQ mask on stream stop to avoid spurious IRQs.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai_sub.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 815ef10..fd7dc77 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -419,8 +419,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
 	}
 
 	/* Enable ITs */
-	regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
-			   SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
 
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
 			   SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
@@ -693,6 +691,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_STOP:
 		dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
 
+		regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+				   SAI_XIMR_MASK, 0);
+
 		regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 				   SAI_XCR1_SAIEN,
 				   (unsigned int)~SAI_XCR1_SAIEN);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 6/7] ASoC: stm32: sai: Fix get reset controller
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:03   ` Olivier Moysan
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Use devm version of reset_control_get function
to manage driver removing properly.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 1258bef..5fe878ac 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	}
 
 	/* reset */
-	rst = reset_control_get_exclusive(&pdev->dev, NULL);
+	rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (!IS_ERR(rst)) {
 		reset_control_assert(rst);
 		udelay(2);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 6/7] ASoC: stm32: sai: Fix get reset controller
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Use devm version of reset_control_get function
to manage driver removing properly.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 1258bef..5fe878ac 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	}
 
 	/* reset */
-	rst = reset_control_get_exclusive(&pdev->dev, NULL);
+	rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (!IS_ERR(rst)) {
 		reset_control_assert(rst);
 		udelay(2);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 6/7] ASoC: stm32: sai: Fix get reset controller
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Use devm version of reset_control_get function
to manage driver removing properly.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 1258bef..5fe878ac 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	}
 
 	/* reset */
-	rst = reset_control_get_exclusive(&pdev->dev, NULL);
+	rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (!IS_ERR(rst)) {
 		reset_control_assert(rst);
 		udelay(2);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 7/7] ASoC: stm32: sai: Add synchronization support
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:03   ` Olivier Moysan
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Add Synchronization support for STM32 SAI.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai.c     | 160 ++++++++++++++++++++++++++++++++++++++++--
 sound/soc/stm/stm32_sai.h     |  22 +++++-
 sound/soc/stm/stm32_sai_sub.c |  95 +++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 5fe878ac..d6f71a3 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -27,6 +28,16 @@
 
 #include "stm32_sai.h"
 
+static LIST_HEAD(sync_providers);
+static DEFINE_MUTEX(sync_mutex);
+
+struct sync_provider {
+	struct list_head link;
+	struct device_node *node;
+	int  (*sync_conf)(void *data, int synco);
+	void *data;
+};
+
 static const struct stm32_sai_conf stm32_sai_conf_f4 = {
 	.version = SAI_STM32F4,
 };
@@ -41,23 +52,143 @@
 	{}
 };
 
+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+{
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_sync_conf_provider(void *data, int synco)
+{
+	struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
+	u32 prev_synco;
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
+		sai->pdev->dev.of_node->name,
+		synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+
+	prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
+	if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
+		dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
+			sai->pdev->dev.of_node->name,
+			prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+		clk_disable_unprepare(sai->pclk);
+		return -EINVAL;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+{
+	struct sync_provider *provider;
+	int ret;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(provider, &sync_providers, link) {
+		if (provider->node == np) {
+			ret = provider->sync_conf(provider->data, synco);
+			mutex_unlock(&sync_mutex);
+			return ret;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+
+	/* SAI sync provider not found */
+	return -ENODEV;
+}
+
+static int stm32_sai_set_sync(struct stm32_sai_data *sai,
+			      struct device_node *np_provider,
+			      int synco, int synci)
+{
+	int ret;
+
+	/* Configure sync client */
+	stm32_sai_sync_conf_client(sai, synci);
+
+	/* Configure sync provider */
+	ret = stm32_sai_set_sync_provider(np_provider, synco);
+
+	return ret;
+}
+
+static int stm32_sai_sync_add_provider(struct platform_device *pdev,
+				       void *data)
+{
+	struct sync_provider *sp;
+
+	sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
+	if (!sp)
+		return -ENOMEM;
+
+	sp->node = of_node_get(pdev->dev.of_node);
+	sp->data = data;
+	sp->sync_conf = &stm32_sai_sync_conf_provider;
+
+	mutex_lock(&sync_mutex);
+	list_add(&sp->link, &sync_providers);
+	mutex_unlock(&sync_mutex);
+
+	return 0;
+}
+
+static void stm32_sai_sync_del_provider(struct device_node *np)
+{
+	struct sync_provider *sp;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(sp, &sync_providers, link) {
+		if (sp->node == np) {
+			list_del(&sp->link);
+			of_node_put(sp->node);
+			break;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+}
+
 static int stm32_sai_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct stm32_sai_data *sai;
 	struct reset_control *rst;
 	struct resource *res;
-	void __iomem *base;
 	const struct of_device_id *of_id;
+	int ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	sai->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sai->base))
+		return PTR_ERR(sai->base);
 
 	of_id = of_match_device(stm32_sai_ids, &pdev->dev);
 	if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	else
 		return -EINVAL;
 
+	if (!STM_SAI_IS_F4(sai)) {
+		sai->pclk = devm_clk_get(&pdev->dev, "pclk");
+		if (IS_ERR(sai->pclk)) {
+			dev_err(&pdev->dev, "missing bus clock pclk\n");
+			return PTR_ERR(sai->pclk);
+		}
+	}
+
 	sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
 	if (IS_ERR(sai->clk_x8k)) {
 		dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -92,16 +231,27 @@ static int stm32_sai_probe(struct platform_device *pdev)
 		reset_control_deassert(rst);
 	}
 
+	ret = stm32_sai_sync_add_provider(pdev, sai);
+	if (ret < 0)
+		return ret;
+	sai->set_sync = &stm32_sai_set_sync;
+
 	sai->pdev = pdev;
 	platform_set_drvdata(pdev, sai);
 
-	return of_platform_populate(np, NULL, NULL, &pdev->dev);
+	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+	if (ret < 0)
+		stm32_sai_sync_del_provider(np);
+
+	return ret;
 }
 
 static int stm32_sai_remove(struct platform_device *pdev)
 {
 	of_platform_depopulate(&pdev->dev);
 
+	stm32_sai_sync_del_provider(pdev->dev.of_node);
+
 	return 0;
 }
 
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc..bb062e7 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
  * details.
  */
 
+#include <linux/bitfield.h>
+
 /******************** SAI Register Map **************************************/
 
-/* common register */
+/* Global configuration register */
 #define STM_SAI_GCR		0x00
 
 /* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
 
 /******************** Bit definition for SAI_GCR register *******************/
 #define SAI_GCR_SYNCIN_SHIFT	0
+#define SAI_GCR_SYNCIN_WDTH	2
 #define SAI_GCR_SYNCIN_MASK	GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
-#define SAI_GCR_SYNCIN_SET(x)	((x) << SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_MAX	FIELD_GET(SAI_GCR_SYNCIN_MASK,\
+				SAI_GCR_SYNCIN_MASK)
 
 #define SAI_GCR_SYNCOUT_SHIFT	4
 #define SAI_GCR_SYNCOUT_MASK	GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
-#define SAI_GCR_SYNCOUT_SET(x)	((x) << SAI_GCR_SYNCOUT_SHIFT)
 
 /******************* Bit definition for SAI_XCR1 register *******************/
 #define SAI_XCR1_RX_TX_SHIFT	0
@@ -231,6 +234,12 @@
 #define STM_SAI_IS_F4(ip)	((ip)->conf->version == SAI_STM32F4)
 #define STM_SAI_IS_H7(ip)	((ip)->conf->version == SAI_STM32H7)
 
+enum stm32_sai_syncout {
+	STM_SAI_SYNC_OUT_NONE,
+	STM_SAI_SYNC_OUT_A,
+	STM_SAI_SYNC_OUT_B,
+};
+
 enum stm32_sai_version {
 	SAI_STM32F4,
 	SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
 /**
  * struct stm32_sai_data - private data of SAI instance driver
  * @pdev: device data pointer
+ * @base: common register bank virtual base address
+ * @pclk: SAI bus clock
  * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
  * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
  * @version: SOC version
  * @irq: SAI interrupt line
+ * @set_sync: pointer to synchro mode configuration callback
  */
 struct stm32_sai_data {
 	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *pclk;
 	struct clk *clk_x8k;
 	struct clk *clk_x11k;
 	struct stm32_sai_conf *conf;
 	int irq;
+	int (*set_sync)(struct stm32_sai_data *sai,
+			struct device_node *np_provider, int synco, int synci);
 };
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fd7dc77..150ad54 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
 #define STM_SAI_IS_SUB_B(x)	((x)->id == STM_SAI_B_ID)
 #define STM_SAI_BLOCK_NAME(x)	(((x)->id == STM_SAI_A_ID) ? "A" : "B")
 
+#define SAI_SYNC_NONE		0x0
+#define SAI_SYNC_INTERNAL	0x1
+#define SAI_SYNC_EXTERNAL	0x2
+
+#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+
 /**
  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
  * @pdev: device data pointer
@@ -65,6 +71,7 @@
  * @cpu_dai: DAI runtime data pointer
  * @substream: PCM substream data pointer
  * @pdata: SAI block parent data pointer
+ * @np_sync_provider: synchronization provider node
  * @sai_ck: kernel clock feeding the SAI clock generator
  * @phys_addr: SAI registers physical base address
  * @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
  * @master: SAI block mode flag. (true=master, false=slave) set at init
  * @fmt: SAI block format. relevant only for custom protocols. set at init
  * @sync: SAI block synchronization mode. (none, internal or external)
+ * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
+ * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
  * @fs_length: frame synchronization length. depends on protocol settings
  * @slots: rx or tx slot number
  * @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
 	struct snd_soc_dai *cpu_dai;
 	struct snd_pcm_substream *substream;
 	struct stm32_sai_data *pdata;
+	struct device_node *np_sync_provider;
 	struct clk *sai_ck;
 	dma_addr_t phys_addr;
 	unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
 	bool master;
 	int fmt;
 	int sync;
+	int synco;
+	int synci;
 	int fs_length;
 	int slots;
 	int slot_width;
@@ -387,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
+
+	/* Set slave mode if sub-block is synchronized with another SAI */
+	if (sai->sync) {
+		dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
+		cr1 |= SAI_XCR1_SLAVE;
+		sai->master = false;
+	}
+
 	cr1_mask |= SAI_XCR1_SLAVE;
 
 	/* do not generate master by default */
@@ -749,6 +769,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	if (STM_SAI_IS_CAPTURE(sai))
 		cr1 |= SAI_XCR1_RX_TX;
 
+	/* Configure synchronization */
+	if (sai->sync == SAI_SYNC_EXTERNAL) {
+		/* Configure synchro client and provider */
+		sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+				     sai->synco, sai->synci);
+	}
+
+	cr1_mask |= SAI_XCR1_SYNCEN_MASK;
+	cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
+
 	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
@@ -835,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *res;
 	void __iomem *base;
+	struct of_phandle_args args;
+	int ret;
 
 	if (!np)
 		return -ENODEV;
@@ -868,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
+	/* Get synchronization property */
+	args.np = NULL;
+	ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
+	if (ret < 0  && ret != -ENOENT) {
+		dev_err(&pdev->dev, "Failed to get st,sync property\n");
+		return ret;
+	}
+
+	sai->sync = SAI_SYNC_NONE;
+	if (args.np) {
+		if (args.np == np) {
+			dev_err(&pdev->dev, "%s sync own reference\n",
+				np->name);
+			of_node_put(args.np);
+			return -EINVAL;
+		}
+
+		sai->np_sync_provider  = of_get_parent(args.np);
+		if (!sai->np_sync_provider) {
+			dev_err(&pdev->dev, "%s parent node not found\n",
+				np->name);
+			of_node_put(args.np);
+			return -ENODEV;
+		}
+
+		sai->sync = SAI_SYNC_INTERNAL;
+		if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
+			if (!STM_SAI_HAS_EXT_SYNC(sai)) {
+				dev_err(&pdev->dev,
+					"External synchro not supported\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+			sai->sync = SAI_SYNC_EXTERNAL;
+
+			sai->synci = args.args[0];
+			if (sai->synci < 1 ||
+			    (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
+				dev_err(&pdev->dev, "Wrong SAI index\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-a") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_A;
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-b") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_B;
+
+			if (!sai->synco) {
+				dev_err(&pdev->dev, "Unknown SAI sub-block\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+		}
+
+		dev_dbg(&pdev->dev, "%s synchronized with %s\n",
+			pdev->name, args.np->full_name);
+	}
+
+	of_node_put(args.np);
 	sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
 	if (IS_ERR(sai->sai_ck)) {
 		dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 7/7] ASoC: stm32: sai: Add synchronization support
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan
  Cc: arnaud.pouliquen, benjamin.gaignard

Add Synchronization support for STM32 SAI.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai.c     | 160 ++++++++++++++++++++++++++++++++++++++++--
 sound/soc/stm/stm32_sai.h     |  22 +++++-
 sound/soc/stm/stm32_sai_sub.c |  95 +++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 5fe878ac..d6f71a3 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -27,6 +28,16 @@
 
 #include "stm32_sai.h"
 
+static LIST_HEAD(sync_providers);
+static DEFINE_MUTEX(sync_mutex);
+
+struct sync_provider {
+	struct list_head link;
+	struct device_node *node;
+	int  (*sync_conf)(void *data, int synco);
+	void *data;
+};
+
 static const struct stm32_sai_conf stm32_sai_conf_f4 = {
 	.version = SAI_STM32F4,
 };
@@ -41,23 +52,143 @@
 	{}
 };
 
+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+{
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_sync_conf_provider(void *data, int synco)
+{
+	struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
+	u32 prev_synco;
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
+		sai->pdev->dev.of_node->name,
+		synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+
+	prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
+	if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
+		dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
+			sai->pdev->dev.of_node->name,
+			prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+		clk_disable_unprepare(sai->pclk);
+		return -EINVAL;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+{
+	struct sync_provider *provider;
+	int ret;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(provider, &sync_providers, link) {
+		if (provider->node == np) {
+			ret = provider->sync_conf(provider->data, synco);
+			mutex_unlock(&sync_mutex);
+			return ret;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+
+	/* SAI sync provider not found */
+	return -ENODEV;
+}
+
+static int stm32_sai_set_sync(struct stm32_sai_data *sai,
+			      struct device_node *np_provider,
+			      int synco, int synci)
+{
+	int ret;
+
+	/* Configure sync client */
+	stm32_sai_sync_conf_client(sai, synci);
+
+	/* Configure sync provider */
+	ret = stm32_sai_set_sync_provider(np_provider, synco);
+
+	return ret;
+}
+
+static int stm32_sai_sync_add_provider(struct platform_device *pdev,
+				       void *data)
+{
+	struct sync_provider *sp;
+
+	sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
+	if (!sp)
+		return -ENOMEM;
+
+	sp->node = of_node_get(pdev->dev.of_node);
+	sp->data = data;
+	sp->sync_conf = &stm32_sai_sync_conf_provider;
+
+	mutex_lock(&sync_mutex);
+	list_add(&sp->link, &sync_providers);
+	mutex_unlock(&sync_mutex);
+
+	return 0;
+}
+
+static void stm32_sai_sync_del_provider(struct device_node *np)
+{
+	struct sync_provider *sp;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(sp, &sync_providers, link) {
+		if (sp->node == np) {
+			list_del(&sp->link);
+			of_node_put(sp->node);
+			break;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+}
+
 static int stm32_sai_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct stm32_sai_data *sai;
 	struct reset_control *rst;
 	struct resource *res;
-	void __iomem *base;
 	const struct of_device_id *of_id;
+	int ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	sai->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sai->base))
+		return PTR_ERR(sai->base);
 
 	of_id = of_match_device(stm32_sai_ids, &pdev->dev);
 	if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	else
 		return -EINVAL;
 
+	if (!STM_SAI_IS_F4(sai)) {
+		sai->pclk = devm_clk_get(&pdev->dev, "pclk");
+		if (IS_ERR(sai->pclk)) {
+			dev_err(&pdev->dev, "missing bus clock pclk\n");
+			return PTR_ERR(sai->pclk);
+		}
+	}
+
 	sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
 	if (IS_ERR(sai->clk_x8k)) {
 		dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -92,16 +231,27 @@ static int stm32_sai_probe(struct platform_device *pdev)
 		reset_control_deassert(rst);
 	}
 
+	ret = stm32_sai_sync_add_provider(pdev, sai);
+	if (ret < 0)
+		return ret;
+	sai->set_sync = &stm32_sai_set_sync;
+
 	sai->pdev = pdev;
 	platform_set_drvdata(pdev, sai);
 
-	return of_platform_populate(np, NULL, NULL, &pdev->dev);
+	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+	if (ret < 0)
+		stm32_sai_sync_del_provider(np);
+
+	return ret;
 }
 
 static int stm32_sai_remove(struct platform_device *pdev)
 {
 	of_platform_depopulate(&pdev->dev);
 
+	stm32_sai_sync_del_provider(pdev->dev.of_node);
+
 	return 0;
 }
 
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc..bb062e7 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
  * details.
  */
 
+#include <linux/bitfield.h>
+
 /******************** SAI Register Map **************************************/
 
-/* common register */
+/* Global configuration register */
 #define STM_SAI_GCR		0x00
 
 /* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
 
 /******************** Bit definition for SAI_GCR register *******************/
 #define SAI_GCR_SYNCIN_SHIFT	0
+#define SAI_GCR_SYNCIN_WDTH	2
 #define SAI_GCR_SYNCIN_MASK	GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
-#define SAI_GCR_SYNCIN_SET(x)	((x) << SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_MAX	FIELD_GET(SAI_GCR_SYNCIN_MASK,\
+				SAI_GCR_SYNCIN_MASK)
 
 #define SAI_GCR_SYNCOUT_SHIFT	4
 #define SAI_GCR_SYNCOUT_MASK	GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
-#define SAI_GCR_SYNCOUT_SET(x)	((x) << SAI_GCR_SYNCOUT_SHIFT)
 
 /******************* Bit definition for SAI_XCR1 register *******************/
 #define SAI_XCR1_RX_TX_SHIFT	0
@@ -231,6 +234,12 @@
 #define STM_SAI_IS_F4(ip)	((ip)->conf->version == SAI_STM32F4)
 #define STM_SAI_IS_H7(ip)	((ip)->conf->version == SAI_STM32H7)
 
+enum stm32_sai_syncout {
+	STM_SAI_SYNC_OUT_NONE,
+	STM_SAI_SYNC_OUT_A,
+	STM_SAI_SYNC_OUT_B,
+};
+
 enum stm32_sai_version {
 	SAI_STM32F4,
 	SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
 /**
  * struct stm32_sai_data - private data of SAI instance driver
  * @pdev: device data pointer
+ * @base: common register bank virtual base address
+ * @pclk: SAI bus clock
  * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
  * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
  * @version: SOC version
  * @irq: SAI interrupt line
+ * @set_sync: pointer to synchro mode configuration callback
  */
 struct stm32_sai_data {
 	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *pclk;
 	struct clk *clk_x8k;
 	struct clk *clk_x11k;
 	struct stm32_sai_conf *conf;
 	int irq;
+	int (*set_sync)(struct stm32_sai_data *sai,
+			struct device_node *np_provider, int synco, int synci);
 };
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fd7dc77..150ad54 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
 #define STM_SAI_IS_SUB_B(x)	((x)->id == STM_SAI_B_ID)
 #define STM_SAI_BLOCK_NAME(x)	(((x)->id == STM_SAI_A_ID) ? "A" : "B")
 
+#define SAI_SYNC_NONE		0x0
+#define SAI_SYNC_INTERNAL	0x1
+#define SAI_SYNC_EXTERNAL	0x2
+
+#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+
 /**
  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
  * @pdev: device data pointer
@@ -65,6 +71,7 @@
  * @cpu_dai: DAI runtime data pointer
  * @substream: PCM substream data pointer
  * @pdata: SAI block parent data pointer
+ * @np_sync_provider: synchronization provider node
  * @sai_ck: kernel clock feeding the SAI clock generator
  * @phys_addr: SAI registers physical base address
  * @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
  * @master: SAI block mode flag. (true=master, false=slave) set at init
  * @fmt: SAI block format. relevant only for custom protocols. set at init
  * @sync: SAI block synchronization mode. (none, internal or external)
+ * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
+ * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
  * @fs_length: frame synchronization length. depends on protocol settings
  * @slots: rx or tx slot number
  * @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
 	struct snd_soc_dai *cpu_dai;
 	struct snd_pcm_substream *substream;
 	struct stm32_sai_data *pdata;
+	struct device_node *np_sync_provider;
 	struct clk *sai_ck;
 	dma_addr_t phys_addr;
 	unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
 	bool master;
 	int fmt;
 	int sync;
+	int synco;
+	int synci;
 	int fs_length;
 	int slots;
 	int slot_width;
@@ -387,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
+
+	/* Set slave mode if sub-block is synchronized with another SAI */
+	if (sai->sync) {
+		dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
+		cr1 |= SAI_XCR1_SLAVE;
+		sai->master = false;
+	}
+
 	cr1_mask |= SAI_XCR1_SLAVE;
 
 	/* do not generate master by default */
@@ -749,6 +769,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	if (STM_SAI_IS_CAPTURE(sai))
 		cr1 |= SAI_XCR1_RX_TX;
 
+	/* Configure synchronization */
+	if (sai->sync == SAI_SYNC_EXTERNAL) {
+		/* Configure synchro client and provider */
+		sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+				     sai->synco, sai->synci);
+	}
+
+	cr1_mask |= SAI_XCR1_SYNCEN_MASK;
+	cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
+
 	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
@@ -835,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *res;
 	void __iomem *base;
+	struct of_phandle_args args;
+	int ret;
 
 	if (!np)
 		return -ENODEV;
@@ -868,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
+	/* Get synchronization property */
+	args.np = NULL;
+	ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
+	if (ret < 0  && ret != -ENOENT) {
+		dev_err(&pdev->dev, "Failed to get st,sync property\n");
+		return ret;
+	}
+
+	sai->sync = SAI_SYNC_NONE;
+	if (args.np) {
+		if (args.np == np) {
+			dev_err(&pdev->dev, "%s sync own reference\n",
+				np->name);
+			of_node_put(args.np);
+			return -EINVAL;
+		}
+
+		sai->np_sync_provider  = of_get_parent(args.np);
+		if (!sai->np_sync_provider) {
+			dev_err(&pdev->dev, "%s parent node not found\n",
+				np->name);
+			of_node_put(args.np);
+			return -ENODEV;
+		}
+
+		sai->sync = SAI_SYNC_INTERNAL;
+		if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
+			if (!STM_SAI_HAS_EXT_SYNC(sai)) {
+				dev_err(&pdev->dev,
+					"External synchro not supported\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+			sai->sync = SAI_SYNC_EXTERNAL;
+
+			sai->synci = args.args[0];
+			if (sai->synci < 1 ||
+			    (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
+				dev_err(&pdev->dev, "Wrong SAI index\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-a") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_A;
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-b") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_B;
+
+			if (!sai->synco) {
+				dev_err(&pdev->dev, "Unknown SAI sub-block\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+		}
+
+		dev_dbg(&pdev->dev, "%s synchronized with %s\n",
+			pdev->name, args.np->full_name);
+	}
+
+	of_node_put(args.np);
 	sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
 	if (IS_ERR(sai->sai_ck)) {
 		dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 7/7] ASoC: stm32: sai: Add synchronization support
@ 2017-10-19 13:03   ` Olivier Moysan
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier Moysan @ 2017-10-19 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Add Synchronization support for STM32 SAI.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
 sound/soc/stm/stm32_sai.c     | 160 ++++++++++++++++++++++++++++++++++++++++--
 sound/soc/stm/stm32_sai.h     |  22 +++++-
 sound/soc/stm/stm32_sai_sub.c |  95 +++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 5fe878ac..d6f71a3 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -27,6 +28,16 @@
 
 #include "stm32_sai.h"
 
+static LIST_HEAD(sync_providers);
+static DEFINE_MUTEX(sync_mutex);
+
+struct sync_provider {
+	struct list_head link;
+	struct device_node *node;
+	int  (*sync_conf)(void *data, int synco);
+	void *data;
+};
+
 static const struct stm32_sai_conf stm32_sai_conf_f4 = {
 	.version = SAI_STM32F4,
 };
@@ -41,23 +52,143 @@
 	{}
 };
 
+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+{
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_sync_conf_provider(void *data, int synco)
+{
+	struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
+	u32 prev_synco;
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
+		sai->pdev->dev.of_node->name,
+		synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+
+	prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
+	if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
+		dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
+			sai->pdev->dev.of_node->name,
+			prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+		clk_disable_unprepare(sai->pclk);
+		return -EINVAL;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+{
+	struct sync_provider *provider;
+	int ret;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(provider, &sync_providers, link) {
+		if (provider->node == np) {
+			ret = provider->sync_conf(provider->data, synco);
+			mutex_unlock(&sync_mutex);
+			return ret;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+
+	/* SAI sync provider not found */
+	return -ENODEV;
+}
+
+static int stm32_sai_set_sync(struct stm32_sai_data *sai,
+			      struct device_node *np_provider,
+			      int synco, int synci)
+{
+	int ret;
+
+	/* Configure sync client */
+	stm32_sai_sync_conf_client(sai, synci);
+
+	/* Configure sync provider */
+	ret = stm32_sai_set_sync_provider(np_provider, synco);
+
+	return ret;
+}
+
+static int stm32_sai_sync_add_provider(struct platform_device *pdev,
+				       void *data)
+{
+	struct sync_provider *sp;
+
+	sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
+	if (!sp)
+		return -ENOMEM;
+
+	sp->node = of_node_get(pdev->dev.of_node);
+	sp->data = data;
+	sp->sync_conf = &stm32_sai_sync_conf_provider;
+
+	mutex_lock(&sync_mutex);
+	list_add(&sp->link, &sync_providers);
+	mutex_unlock(&sync_mutex);
+
+	return 0;
+}
+
+static void stm32_sai_sync_del_provider(struct device_node *np)
+{
+	struct sync_provider *sp;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(sp, &sync_providers, link) {
+		if (sp->node == np) {
+			list_del(&sp->link);
+			of_node_put(sp->node);
+			break;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+}
+
 static int stm32_sai_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct stm32_sai_data *sai;
 	struct reset_control *rst;
 	struct resource *res;
-	void __iomem *base;
 	const struct of_device_id *of_id;
+	int ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	sai->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sai->base))
+		return PTR_ERR(sai->base);
 
 	of_id = of_match_device(stm32_sai_ids, &pdev->dev);
 	if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	else
 		return -EINVAL;
 
+	if (!STM_SAI_IS_F4(sai)) {
+		sai->pclk = devm_clk_get(&pdev->dev, "pclk");
+		if (IS_ERR(sai->pclk)) {
+			dev_err(&pdev->dev, "missing bus clock pclk\n");
+			return PTR_ERR(sai->pclk);
+		}
+	}
+
 	sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
 	if (IS_ERR(sai->clk_x8k)) {
 		dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -92,16 +231,27 @@ static int stm32_sai_probe(struct platform_device *pdev)
 		reset_control_deassert(rst);
 	}
 
+	ret = stm32_sai_sync_add_provider(pdev, sai);
+	if (ret < 0)
+		return ret;
+	sai->set_sync = &stm32_sai_set_sync;
+
 	sai->pdev = pdev;
 	platform_set_drvdata(pdev, sai);
 
-	return of_platform_populate(np, NULL, NULL, &pdev->dev);
+	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+	if (ret < 0)
+		stm32_sai_sync_del_provider(np);
+
+	return ret;
 }
 
 static int stm32_sai_remove(struct platform_device *pdev)
 {
 	of_platform_depopulate(&pdev->dev);
 
+	stm32_sai_sync_del_provider(pdev->dev.of_node);
+
 	return 0;
 }
 
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc..bb062e7 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
  * details.
  */
 
+#include <linux/bitfield.h>
+
 /******************** SAI Register Map **************************************/
 
-/* common register */
+/* Global configuration register */
 #define STM_SAI_GCR		0x00
 
 /* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
 
 /******************** Bit definition for SAI_GCR register *******************/
 #define SAI_GCR_SYNCIN_SHIFT	0
+#define SAI_GCR_SYNCIN_WDTH	2
 #define SAI_GCR_SYNCIN_MASK	GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
-#define SAI_GCR_SYNCIN_SET(x)	((x) << SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_MAX	FIELD_GET(SAI_GCR_SYNCIN_MASK,\
+				SAI_GCR_SYNCIN_MASK)
 
 #define SAI_GCR_SYNCOUT_SHIFT	4
 #define SAI_GCR_SYNCOUT_MASK	GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
-#define SAI_GCR_SYNCOUT_SET(x)	((x) << SAI_GCR_SYNCOUT_SHIFT)
 
 /******************* Bit definition for SAI_XCR1 register *******************/
 #define SAI_XCR1_RX_TX_SHIFT	0
@@ -231,6 +234,12 @@
 #define STM_SAI_IS_F4(ip)	((ip)->conf->version == SAI_STM32F4)
 #define STM_SAI_IS_H7(ip)	((ip)->conf->version == SAI_STM32H7)
 
+enum stm32_sai_syncout {
+	STM_SAI_SYNC_OUT_NONE,
+	STM_SAI_SYNC_OUT_A,
+	STM_SAI_SYNC_OUT_B,
+};
+
 enum stm32_sai_version {
 	SAI_STM32F4,
 	SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
 /**
  * struct stm32_sai_data - private data of SAI instance driver
  * @pdev: device data pointer
+ * @base: common register bank virtual base address
+ * @pclk: SAI bus clock
  * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
  * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
  * @version: SOC version
  * @irq: SAI interrupt line
+ * @set_sync: pointer to synchro mode configuration callback
  */
 struct stm32_sai_data {
 	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *pclk;
 	struct clk *clk_x8k;
 	struct clk *clk_x11k;
 	struct stm32_sai_conf *conf;
 	int irq;
+	int (*set_sync)(struct stm32_sai_data *sai,
+			struct device_node *np_provider, int synco, int synci);
 };
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fd7dc77..150ad54 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
 #define STM_SAI_IS_SUB_B(x)	((x)->id == STM_SAI_B_ID)
 #define STM_SAI_BLOCK_NAME(x)	(((x)->id == STM_SAI_A_ID) ? "A" : "B")
 
+#define SAI_SYNC_NONE		0x0
+#define SAI_SYNC_INTERNAL	0x1
+#define SAI_SYNC_EXTERNAL	0x2
+
+#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+
 /**
  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
  * @pdev: device data pointer
@@ -65,6 +71,7 @@
  * @cpu_dai: DAI runtime data pointer
  * @substream: PCM substream data pointer
  * @pdata: SAI block parent data pointer
+ * @np_sync_provider: synchronization provider node
  * @sai_ck: kernel clock feeding the SAI clock generator
  * @phys_addr: SAI registers physical base address
  * @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
  * @master: SAI block mode flag. (true=master, false=slave) set at init
  * @fmt: SAI block format. relevant only for custom protocols. set at init
  * @sync: SAI block synchronization mode. (none, internal or external)
+ * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
+ * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
  * @fs_length: frame synchronization length. depends on protocol settings
  * @slots: rx or tx slot number
  * @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
 	struct snd_soc_dai *cpu_dai;
 	struct snd_pcm_substream *substream;
 	struct stm32_sai_data *pdata;
+	struct device_node *np_sync_provider;
 	struct clk *sai_ck;
 	dma_addr_t phys_addr;
 	unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
 	bool master;
 	int fmt;
 	int sync;
+	int synco;
+	int synci;
 	int fs_length;
 	int slots;
 	int slot_width;
@@ -387,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
+
+	/* Set slave mode if sub-block is synchronized with another SAI */
+	if (sai->sync) {
+		dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
+		cr1 |= SAI_XCR1_SLAVE;
+		sai->master = false;
+	}
+
 	cr1_mask |= SAI_XCR1_SLAVE;
 
 	/* do not generate master by default */
@@ -749,6 +769,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	if (STM_SAI_IS_CAPTURE(sai))
 		cr1 |= SAI_XCR1_RX_TX;
 
+	/* Configure synchronization */
+	if (sai->sync == SAI_SYNC_EXTERNAL) {
+		/* Configure synchro client and provider */
+		sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+				     sai->synco, sai->synci);
+	}
+
+	cr1_mask |= SAI_XCR1_SYNCEN_MASK;
+	cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
+
 	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
@@ -835,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *res;
 	void __iomem *base;
+	struct of_phandle_args args;
+	int ret;
 
 	if (!np)
 		return -ENODEV;
@@ -868,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
+	/* Get synchronization property */
+	args.np = NULL;
+	ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
+	if (ret < 0  && ret != -ENOENT) {
+		dev_err(&pdev->dev, "Failed to get st,sync property\n");
+		return ret;
+	}
+
+	sai->sync = SAI_SYNC_NONE;
+	if (args.np) {
+		if (args.np == np) {
+			dev_err(&pdev->dev, "%s sync own reference\n",
+				np->name);
+			of_node_put(args.np);
+			return -EINVAL;
+		}
+
+		sai->np_sync_provider  = of_get_parent(args.np);
+		if (!sai->np_sync_provider) {
+			dev_err(&pdev->dev, "%s parent node not found\n",
+				np->name);
+			of_node_put(args.np);
+			return -ENODEV;
+		}
+
+		sai->sync = SAI_SYNC_INTERNAL;
+		if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
+			if (!STM_SAI_HAS_EXT_SYNC(sai)) {
+				dev_err(&pdev->dev,
+					"External synchro not supported\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+			sai->sync = SAI_SYNC_EXTERNAL;
+
+			sai->synci = args.args[0];
+			if (sai->synci < 1 ||
+			    (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
+				dev_err(&pdev->dev, "Wrong SAI index\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-a") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_A;
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-b") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_B;
+
+			if (!sai->synco) {
+				dev_err(&pdev->dev, "Unknown SAI sub-block\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+		}
+
+		dev_dbg(&pdev->dev, "%s synchronized with %s\n",
+			pdev->name, args.np->full_name);
+	}
+
+	of_node_put(args.np);
 	sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
 	if (IS_ERR(sai->sai_ck)) {
 		dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
  2017-10-19 13:03 ` Olivier Moysan
  (?)
@ 2017-10-19 13:27   ` Olivier MOYSAN
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier MOYSAN @ 2017-10-19 13:27 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	Alexandre TORGUE, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel
  Cc: Arnaud POULIQUEN, Benjamin GAIGNARD

Please ignore "[INTERNAL]" in subject.
Sorry for this unappropriated header.

On 10/19/2017 03:03 PM, Olivier Moysan wrote:
> This patch-set adds support of synchronization features for SAI interface.
> It also adds minor fixes and improvements.
> 
> Olivier Moysan (7):
>    ASoC: stm32: Add synchronization to SAI bindings
>    ASoC: stm32: sai: Move static settings to DAI init
>    ASoC: stm32: sai: Fix DMA burst size
>    ASoC: stm32: sai: fix stop management in isr
>    ASoC: stm32: sai: Remove spurious IRQs on stop
>    ASoC: stm32: sai: Fix get reset controller
>    ASoC: stm32: sai: Add synchronization support
> 
>   .../devicetree/bindings/sound/st,stm32-sai.txt     |  14 +-
>   sound/soc/stm/stm32_sai.c                          | 162 ++++++++++++++++++++-
>   sound/soc/stm/stm32_sai.h                          |  22 ++-
>   sound/soc/stm/stm32_sai_sub.c                      | 156 +++++++++++++++++---
>   4 files changed, 318 insertions(+), 36 deletions(-)
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
@ 2017-10-19 13:27   ` Olivier MOYSAN
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier MOYSAN @ 2017-10-19 13:27 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	Alexandre TORGUE, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel
  Cc: Arnaud POULIQUEN, Benjamin GAIGNARD

Please ignore "[INTERNAL]" in subject.
Sorry for this unappropriated header.

On 10/19/2017 03:03 PM, Olivier Moysan wrote:
> This patch-set adds support of synchronization features for SAI interface.
> It also adds minor fixes and improvements.
> 
> Olivier Moysan (7):
>    ASoC: stm32: Add synchronization to SAI bindings
>    ASoC: stm32: sai: Move static settings to DAI init
>    ASoC: stm32: sai: Fix DMA burst size
>    ASoC: stm32: sai: fix stop management in isr
>    ASoC: stm32: sai: Remove spurious IRQs on stop
>    ASoC: stm32: sai: Fix get reset controller
>    ASoC: stm32: sai: Add synchronization support
> 
>   .../devicetree/bindings/sound/st,stm32-sai.txt     |  14 +-
>   sound/soc/stm/stm32_sai.c                          | 162 ++++++++++++++++++++-
>   sound/soc/stm/stm32_sai.h                          |  22 ++-
>   sound/soc/stm/stm32_sai_sub.c                      | 156 +++++++++++++++++---
>   4 files changed, 318 insertions(+), 36 deletions(-)
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
@ 2017-10-19 13:27   ` Olivier MOYSAN
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier MOYSAN @ 2017-10-19 13:27 UTC (permalink / raw)
  To: linux-arm-kernel

Please ignore "[INTERNAL]" in subject.
Sorry for this unappropriated header.

On 10/19/2017 03:03 PM, Olivier Moysan wrote:
> This patch-set adds support of synchronization features for SAI interface.
> It also adds minor fixes and improvements.
> 
> Olivier Moysan (7):
>    ASoC: stm32: Add synchronization to SAI bindings
>    ASoC: stm32: sai: Move static settings to DAI init
>    ASoC: stm32: sai: Fix DMA burst size
>    ASoC: stm32: sai: fix stop management in isr
>    ASoC: stm32: sai: Remove spurious IRQs on stop
>    ASoC: stm32: sai: Fix get reset controller
>    ASoC: stm32: sai: Add synchronization support
> 
>   .../devicetree/bindings/sound/st,stm32-sai.txt     |  14 +-
>   sound/soc/stm/stm32_sai.c                          | 162 ++++++++++++++++++++-
>   sound/soc/stm/stm32_sai.h                          |  22 ++-
>   sound/soc/stm/stm32_sai_sub.c                      | 156 +++++++++++++++++---
>   4 files changed, 318 insertions(+), 36 deletions(-)
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
  2017-10-19 13:03   ` Olivier Moysan
  (?)
@ 2017-10-21 10:16     ` Mark Brown
  -1 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:16 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: lgirdwood, perex, tiwai, mcoquelin.stm32, alexandre.torgue,
	alsa-devel, robh, mark.rutland, devicetree, linux-arm-kernel,
	kernel, linux-kernel, arnaud.pouliquen, benjamin.gaignard

[-- Attachment #1: Type: text/plain, Size: 236 bytes --]

On Thu, Oct 19, 2017 at 03:03:20PM +0200, Olivier Moysan wrote:
> Add check on substream validity.

Fixes should go at the start of the series so they can be applied
separately and sent to Linus without having to wait for new features.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-10-21 10:16     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:16 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: mark.rutland, robh, alsa-devel, alexandre.torgue, devicetree,
	linux-kernel, arnaud.pouliquen, tiwai, lgirdwood,
	mcoquelin.stm32, benjamin.gaignard, linux-arm-kernel, kernel


[-- Attachment #1.1: Type: text/plain, Size: 236 bytes --]

On Thu, Oct 19, 2017 at 03:03:20PM +0200, Olivier Moysan wrote:
> Add check on substream validity.

Fixes should go at the start of the series so they can be applied
separately and sent to Linus without having to wait for new features.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-10-21 10:16     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Oct 19, 2017 at 03:03:20PM +0200, Olivier Moysan wrote:
> Add check on substream validity.

Fixes should go at the start of the series so they can be applied
separately and sent to Linus without having to wait for new features.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171021/7472ee7a/attachment.sig>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Add synchronization support" to the asoc tree
  2017-10-19 13:03   ` Olivier Moysan
  (?)
@ 2017-10-21 10:31     ` Mark Brown
  -1 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: olivier moysan, Mark Brown, lgirdwood, broonie, perex, tiwai,
	mcoquelin.stm32, alexandre.torgue, alsa-devel, robh,
	mark.rutland, devicetree, linux-arm-kernel, kernel, linux-kernel,
	olivier.moysan, arnaud.pouliquen, benjamin.gaignard, alsa-devel

The patch

   ASoC: stm32: sai: Add synchronization support

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 5914d285f6b782892a91d6621723fdc41a775b15 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:23 +0200
Subject: [PATCH] ASoC: stm32: sai: Add synchronization support

Add Synchronization support for STM32 SAI.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai.c     | 160 ++++++++++++++++++++++++++++++++++++++++--
 sound/soc/stm/stm32_sai.h     |  22 +++++-
 sound/soc/stm/stm32_sai_sub.c |  95 +++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 5fe878ace605..d6f71a3406e9 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -27,6 +28,16 @@
 
 #include "stm32_sai.h"
 
+static LIST_HEAD(sync_providers);
+static DEFINE_MUTEX(sync_mutex);
+
+struct sync_provider {
+	struct list_head link;
+	struct device_node *node;
+	int  (*sync_conf)(void *data, int synco);
+	void *data;
+};
+
 static const struct stm32_sai_conf stm32_sai_conf_f4 = {
 	.version = SAI_STM32F4,
 };
@@ -41,23 +52,143 @@ static const struct of_device_id stm32_sai_ids[] = {
 	{}
 };
 
+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+{
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_sync_conf_provider(void *data, int synco)
+{
+	struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
+	u32 prev_synco;
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
+		sai->pdev->dev.of_node->name,
+		synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+
+	prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
+	if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
+		dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
+			sai->pdev->dev.of_node->name,
+			prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+		clk_disable_unprepare(sai->pclk);
+		return -EINVAL;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+{
+	struct sync_provider *provider;
+	int ret;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(provider, &sync_providers, link) {
+		if (provider->node == np) {
+			ret = provider->sync_conf(provider->data, synco);
+			mutex_unlock(&sync_mutex);
+			return ret;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+
+	/* SAI sync provider not found */
+	return -ENODEV;
+}
+
+static int stm32_sai_set_sync(struct stm32_sai_data *sai,
+			      struct device_node *np_provider,
+			      int synco, int synci)
+{
+	int ret;
+
+	/* Configure sync client */
+	stm32_sai_sync_conf_client(sai, synci);
+
+	/* Configure sync provider */
+	ret = stm32_sai_set_sync_provider(np_provider, synco);
+
+	return ret;
+}
+
+static int stm32_sai_sync_add_provider(struct platform_device *pdev,
+				       void *data)
+{
+	struct sync_provider *sp;
+
+	sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
+	if (!sp)
+		return -ENOMEM;
+
+	sp->node = of_node_get(pdev->dev.of_node);
+	sp->data = data;
+	sp->sync_conf = &stm32_sai_sync_conf_provider;
+
+	mutex_lock(&sync_mutex);
+	list_add(&sp->link, &sync_providers);
+	mutex_unlock(&sync_mutex);
+
+	return 0;
+}
+
+static void stm32_sai_sync_del_provider(struct device_node *np)
+{
+	struct sync_provider *sp;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(sp, &sync_providers, link) {
+		if (sp->node == np) {
+			list_del(&sp->link);
+			of_node_put(sp->node);
+			break;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+}
+
 static int stm32_sai_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct stm32_sai_data *sai;
 	struct reset_control *rst;
 	struct resource *res;
-	void __iomem *base;
 	const struct of_device_id *of_id;
+	int ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	sai->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sai->base))
+		return PTR_ERR(sai->base);
 
 	of_id = of_match_device(stm32_sai_ids, &pdev->dev);
 	if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	else
 		return -EINVAL;
 
+	if (!STM_SAI_IS_F4(sai)) {
+		sai->pclk = devm_clk_get(&pdev->dev, "pclk");
+		if (IS_ERR(sai->pclk)) {
+			dev_err(&pdev->dev, "missing bus clock pclk\n");
+			return PTR_ERR(sai->pclk);
+		}
+	}
+
 	sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
 	if (IS_ERR(sai->clk_x8k)) {
 		dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -92,16 +231,27 @@ static int stm32_sai_probe(struct platform_device *pdev)
 		reset_control_deassert(rst);
 	}
 
+	ret = stm32_sai_sync_add_provider(pdev, sai);
+	if (ret < 0)
+		return ret;
+	sai->set_sync = &stm32_sai_set_sync;
+
 	sai->pdev = pdev;
 	platform_set_drvdata(pdev, sai);
 
-	return of_platform_populate(np, NULL, NULL, &pdev->dev);
+	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+	if (ret < 0)
+		stm32_sai_sync_del_provider(np);
+
+	return ret;
 }
 
 static int stm32_sai_remove(struct platform_device *pdev)
 {
 	of_platform_depopulate(&pdev->dev);
 
+	stm32_sai_sync_del_provider(pdev->dev.of_node);
+
 	return 0;
 }
 
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc62d9..bb062e70de63 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
  * details.
  */
 
+#include <linux/bitfield.h>
+
 /******************** SAI Register Map **************************************/
 
-/* common register */
+/* Global configuration register */
 #define STM_SAI_GCR		0x00
 
 /* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
 
 /******************** Bit definition for SAI_GCR register *******************/
 #define SAI_GCR_SYNCIN_SHIFT	0
+#define SAI_GCR_SYNCIN_WDTH	2
 #define SAI_GCR_SYNCIN_MASK	GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
-#define SAI_GCR_SYNCIN_SET(x)	((x) << SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_MAX	FIELD_GET(SAI_GCR_SYNCIN_MASK,\
+				SAI_GCR_SYNCIN_MASK)
 
 #define SAI_GCR_SYNCOUT_SHIFT	4
 #define SAI_GCR_SYNCOUT_MASK	GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
-#define SAI_GCR_SYNCOUT_SET(x)	((x) << SAI_GCR_SYNCOUT_SHIFT)
 
 /******************* Bit definition for SAI_XCR1 register *******************/
 #define SAI_XCR1_RX_TX_SHIFT	0
@@ -231,6 +234,12 @@
 #define STM_SAI_IS_F4(ip)	((ip)->conf->version == SAI_STM32F4)
 #define STM_SAI_IS_H7(ip)	((ip)->conf->version == SAI_STM32H7)
 
+enum stm32_sai_syncout {
+	STM_SAI_SYNC_OUT_NONE,
+	STM_SAI_SYNC_OUT_A,
+	STM_SAI_SYNC_OUT_B,
+};
+
 enum stm32_sai_version {
 	SAI_STM32F4,
 	SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
 /**
  * struct stm32_sai_data - private data of SAI instance driver
  * @pdev: device data pointer
+ * @base: common register bank virtual base address
+ * @pclk: SAI bus clock
  * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
  * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
  * @version: SOC version
  * @irq: SAI interrupt line
+ * @set_sync: pointer to synchro mode configuration callback
  */
 struct stm32_sai_data {
 	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *pclk;
 	struct clk *clk_x8k;
 	struct clk *clk_x11k;
 	struct stm32_sai_conf *conf;
 	int irq;
+	int (*set_sync)(struct stm32_sai_data *sai,
+			struct device_node *np_provider, int synco, int synci);
 };
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fd7dc7760f58..150ad546d8b9 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
 #define STM_SAI_IS_SUB_B(x)	((x)->id == STM_SAI_B_ID)
 #define STM_SAI_BLOCK_NAME(x)	(((x)->id == STM_SAI_A_ID) ? "A" : "B")
 
+#define SAI_SYNC_NONE		0x0
+#define SAI_SYNC_INTERNAL	0x1
+#define SAI_SYNC_EXTERNAL	0x2
+
+#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+
 /**
  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
  * @pdev: device data pointer
@@ -65,6 +71,7 @@
  * @cpu_dai: DAI runtime data pointer
  * @substream: PCM substream data pointer
  * @pdata: SAI block parent data pointer
+ * @np_sync_provider: synchronization provider node
  * @sai_ck: kernel clock feeding the SAI clock generator
  * @phys_addr: SAI registers physical base address
  * @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
  * @master: SAI block mode flag. (true=master, false=slave) set at init
  * @fmt: SAI block format. relevant only for custom protocols. set at init
  * @sync: SAI block synchronization mode. (none, internal or external)
+ * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
+ * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
  * @fs_length: frame synchronization length. depends on protocol settings
  * @slots: rx or tx slot number
  * @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
 	struct snd_soc_dai *cpu_dai;
 	struct snd_pcm_substream *substream;
 	struct stm32_sai_data *pdata;
+	struct device_node *np_sync_provider;
 	struct clk *sai_ck;
 	dma_addr_t phys_addr;
 	unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
 	bool master;
 	int fmt;
 	int sync;
+	int synco;
+	int synci;
 	int fs_length;
 	int slots;
 	int slot_width;
@@ -387,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
+
+	/* Set slave mode if sub-block is synchronized with another SAI */
+	if (sai->sync) {
+		dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
+		cr1 |= SAI_XCR1_SLAVE;
+		sai->master = false;
+	}
+
 	cr1_mask |= SAI_XCR1_SLAVE;
 
 	/* do not generate master by default */
@@ -749,6 +769,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	if (STM_SAI_IS_CAPTURE(sai))
 		cr1 |= SAI_XCR1_RX_TX;
 
+	/* Configure synchronization */
+	if (sai->sync == SAI_SYNC_EXTERNAL) {
+		/* Configure synchro client and provider */
+		sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+				     sai->synco, sai->synci);
+	}
+
+	cr1_mask |= SAI_XCR1_SYNCEN_MASK;
+	cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
+
 	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
@@ -835,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *res;
 	void __iomem *base;
+	struct of_phandle_args args;
+	int ret;
 
 	if (!np)
 		return -ENODEV;
@@ -868,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
+	/* Get synchronization property */
+	args.np = NULL;
+	ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
+	if (ret < 0  && ret != -ENOENT) {
+		dev_err(&pdev->dev, "Failed to get st,sync property\n");
+		return ret;
+	}
+
+	sai->sync = SAI_SYNC_NONE;
+	if (args.np) {
+		if (args.np == np) {
+			dev_err(&pdev->dev, "%s sync own reference\n",
+				np->name);
+			of_node_put(args.np);
+			return -EINVAL;
+		}
+
+		sai->np_sync_provider  = of_get_parent(args.np);
+		if (!sai->np_sync_provider) {
+			dev_err(&pdev->dev, "%s parent node not found\n",
+				np->name);
+			of_node_put(args.np);
+			return -ENODEV;
+		}
+
+		sai->sync = SAI_SYNC_INTERNAL;
+		if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
+			if (!STM_SAI_HAS_EXT_SYNC(sai)) {
+				dev_err(&pdev->dev,
+					"External synchro not supported\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+			sai->sync = SAI_SYNC_EXTERNAL;
+
+			sai->synci = args.args[0];
+			if (sai->synci < 1 ||
+			    (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
+				dev_err(&pdev->dev, "Wrong SAI index\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-a") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_A;
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-b") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_B;
+
+			if (!sai->synco) {
+				dev_err(&pdev->dev, "Unknown SAI sub-block\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+		}
+
+		dev_dbg(&pdev->dev, "%s synchronized with %s\n",
+			pdev->name, args.np->full_name);
+	}
+
+	of_node_put(args.np);
 	sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
 	if (IS_ERR(sai->sai_ck)) {
 		dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Add synchronization support" to the asoc tree
@ 2017-10-21 10:31     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  Cc: mark.rutland, robh, alsa-devel, olivier.moysan, alexandre.torgue,
	devicetree, linux-kernel, arnaud.pouliquen, tiwai, lgirdwood,
	broonie, mcoquelin.stm32, benjamin.gaignard, linux-arm-kernel,
	kernel

The patch

   ASoC: stm32: sai: Add synchronization support

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 5914d285f6b782892a91d6621723fdc41a775b15 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:23 +0200
Subject: [PATCH] ASoC: stm32: sai: Add synchronization support

Add Synchronization support for STM32 SAI.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai.c     | 160 ++++++++++++++++++++++++++++++++++++++++--
 sound/soc/stm/stm32_sai.h     |  22 +++++-
 sound/soc/stm/stm32_sai_sub.c |  95 +++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 5fe878ace605..d6f71a3406e9 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -27,6 +28,16 @@
 
 #include "stm32_sai.h"
 
+static LIST_HEAD(sync_providers);
+static DEFINE_MUTEX(sync_mutex);
+
+struct sync_provider {
+	struct list_head link;
+	struct device_node *node;
+	int  (*sync_conf)(void *data, int synco);
+	void *data;
+};
+
 static const struct stm32_sai_conf stm32_sai_conf_f4 = {
 	.version = SAI_STM32F4,
 };
@@ -41,23 +52,143 @@ static const struct of_device_id stm32_sai_ids[] = {
 	{}
 };
 
+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+{
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_sync_conf_provider(void *data, int synco)
+{
+	struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
+	u32 prev_synco;
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
+		sai->pdev->dev.of_node->name,
+		synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+
+	prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
+	if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
+		dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
+			sai->pdev->dev.of_node->name,
+			prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+		clk_disable_unprepare(sai->pclk);
+		return -EINVAL;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+{
+	struct sync_provider *provider;
+	int ret;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(provider, &sync_providers, link) {
+		if (provider->node == np) {
+			ret = provider->sync_conf(provider->data, synco);
+			mutex_unlock(&sync_mutex);
+			return ret;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+
+	/* SAI sync provider not found */
+	return -ENODEV;
+}
+
+static int stm32_sai_set_sync(struct stm32_sai_data *sai,
+			      struct device_node *np_provider,
+			      int synco, int synci)
+{
+	int ret;
+
+	/* Configure sync client */
+	stm32_sai_sync_conf_client(sai, synci);
+
+	/* Configure sync provider */
+	ret = stm32_sai_set_sync_provider(np_provider, synco);
+
+	return ret;
+}
+
+static int stm32_sai_sync_add_provider(struct platform_device *pdev,
+				       void *data)
+{
+	struct sync_provider *sp;
+
+	sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
+	if (!sp)
+		return -ENOMEM;
+
+	sp->node = of_node_get(pdev->dev.of_node);
+	sp->data = data;
+	sp->sync_conf = &stm32_sai_sync_conf_provider;
+
+	mutex_lock(&sync_mutex);
+	list_add(&sp->link, &sync_providers);
+	mutex_unlock(&sync_mutex);
+
+	return 0;
+}
+
+static void stm32_sai_sync_del_provider(struct device_node *np)
+{
+	struct sync_provider *sp;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(sp, &sync_providers, link) {
+		if (sp->node == np) {
+			list_del(&sp->link);
+			of_node_put(sp->node);
+			break;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+}
+
 static int stm32_sai_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct stm32_sai_data *sai;
 	struct reset_control *rst;
 	struct resource *res;
-	void __iomem *base;
 	const struct of_device_id *of_id;
+	int ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	sai->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sai->base))
+		return PTR_ERR(sai->base);
 
 	of_id = of_match_device(stm32_sai_ids, &pdev->dev);
 	if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	else
 		return -EINVAL;
 
+	if (!STM_SAI_IS_F4(sai)) {
+		sai->pclk = devm_clk_get(&pdev->dev, "pclk");
+		if (IS_ERR(sai->pclk)) {
+			dev_err(&pdev->dev, "missing bus clock pclk\n");
+			return PTR_ERR(sai->pclk);
+		}
+	}
+
 	sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
 	if (IS_ERR(sai->clk_x8k)) {
 		dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -92,16 +231,27 @@ static int stm32_sai_probe(struct platform_device *pdev)
 		reset_control_deassert(rst);
 	}
 
+	ret = stm32_sai_sync_add_provider(pdev, sai);
+	if (ret < 0)
+		return ret;
+	sai->set_sync = &stm32_sai_set_sync;
+
 	sai->pdev = pdev;
 	platform_set_drvdata(pdev, sai);
 
-	return of_platform_populate(np, NULL, NULL, &pdev->dev);
+	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+	if (ret < 0)
+		stm32_sai_sync_del_provider(np);
+
+	return ret;
 }
 
 static int stm32_sai_remove(struct platform_device *pdev)
 {
 	of_platform_depopulate(&pdev->dev);
 
+	stm32_sai_sync_del_provider(pdev->dev.of_node);
+
 	return 0;
 }
 
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc62d9..bb062e70de63 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
  * details.
  */
 
+#include <linux/bitfield.h>
+
 /******************** SAI Register Map **************************************/
 
-/* common register */
+/* Global configuration register */
 #define STM_SAI_GCR		0x00
 
 /* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
 
 /******************** Bit definition for SAI_GCR register *******************/
 #define SAI_GCR_SYNCIN_SHIFT	0
+#define SAI_GCR_SYNCIN_WDTH	2
 #define SAI_GCR_SYNCIN_MASK	GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
-#define SAI_GCR_SYNCIN_SET(x)	((x) << SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_MAX	FIELD_GET(SAI_GCR_SYNCIN_MASK,\
+				SAI_GCR_SYNCIN_MASK)
 
 #define SAI_GCR_SYNCOUT_SHIFT	4
 #define SAI_GCR_SYNCOUT_MASK	GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
-#define SAI_GCR_SYNCOUT_SET(x)	((x) << SAI_GCR_SYNCOUT_SHIFT)
 
 /******************* Bit definition for SAI_XCR1 register *******************/
 #define SAI_XCR1_RX_TX_SHIFT	0
@@ -231,6 +234,12 @@
 #define STM_SAI_IS_F4(ip)	((ip)->conf->version == SAI_STM32F4)
 #define STM_SAI_IS_H7(ip)	((ip)->conf->version == SAI_STM32H7)
 
+enum stm32_sai_syncout {
+	STM_SAI_SYNC_OUT_NONE,
+	STM_SAI_SYNC_OUT_A,
+	STM_SAI_SYNC_OUT_B,
+};
+
 enum stm32_sai_version {
 	SAI_STM32F4,
 	SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
 /**
  * struct stm32_sai_data - private data of SAI instance driver
  * @pdev: device data pointer
+ * @base: common register bank virtual base address
+ * @pclk: SAI bus clock
  * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
  * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
  * @version: SOC version
  * @irq: SAI interrupt line
+ * @set_sync: pointer to synchro mode configuration callback
  */
 struct stm32_sai_data {
 	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *pclk;
 	struct clk *clk_x8k;
 	struct clk *clk_x11k;
 	struct stm32_sai_conf *conf;
 	int irq;
+	int (*set_sync)(struct stm32_sai_data *sai,
+			struct device_node *np_provider, int synco, int synci);
 };
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fd7dc7760f58..150ad546d8b9 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
 #define STM_SAI_IS_SUB_B(x)	((x)->id == STM_SAI_B_ID)
 #define STM_SAI_BLOCK_NAME(x)	(((x)->id == STM_SAI_A_ID) ? "A" : "B")
 
+#define SAI_SYNC_NONE		0x0
+#define SAI_SYNC_INTERNAL	0x1
+#define SAI_SYNC_EXTERNAL	0x2
+
+#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+
 /**
  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
  * @pdev: device data pointer
@@ -65,6 +71,7 @@
  * @cpu_dai: DAI runtime data pointer
  * @substream: PCM substream data pointer
  * @pdata: SAI block parent data pointer
+ * @np_sync_provider: synchronization provider node
  * @sai_ck: kernel clock feeding the SAI clock generator
  * @phys_addr: SAI registers physical base address
  * @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
  * @master: SAI block mode flag. (true=master, false=slave) set at init
  * @fmt: SAI block format. relevant only for custom protocols. set at init
  * @sync: SAI block synchronization mode. (none, internal or external)
+ * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
+ * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
  * @fs_length: frame synchronization length. depends on protocol settings
  * @slots: rx or tx slot number
  * @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
 	struct snd_soc_dai *cpu_dai;
 	struct snd_pcm_substream *substream;
 	struct stm32_sai_data *pdata;
+	struct device_node *np_sync_provider;
 	struct clk *sai_ck;
 	dma_addr_t phys_addr;
 	unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
 	bool master;
 	int fmt;
 	int sync;
+	int synco;
+	int synci;
 	int fs_length;
 	int slots;
 	int slot_width;
@@ -387,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
+
+	/* Set slave mode if sub-block is synchronized with another SAI */
+	if (sai->sync) {
+		dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
+		cr1 |= SAI_XCR1_SLAVE;
+		sai->master = false;
+	}
+
 	cr1_mask |= SAI_XCR1_SLAVE;
 
 	/* do not generate master by default */
@@ -749,6 +769,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	if (STM_SAI_IS_CAPTURE(sai))
 		cr1 |= SAI_XCR1_RX_TX;
 
+	/* Configure synchronization */
+	if (sai->sync == SAI_SYNC_EXTERNAL) {
+		/* Configure synchro client and provider */
+		sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+				     sai->synco, sai->synci);
+	}
+
+	cr1_mask |= SAI_XCR1_SYNCEN_MASK;
+	cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
+
 	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
@@ -835,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *res;
 	void __iomem *base;
+	struct of_phandle_args args;
+	int ret;
 
 	if (!np)
 		return -ENODEV;
@@ -868,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
+	/* Get synchronization property */
+	args.np = NULL;
+	ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
+	if (ret < 0  && ret != -ENOENT) {
+		dev_err(&pdev->dev, "Failed to get st,sync property\n");
+		return ret;
+	}
+
+	sai->sync = SAI_SYNC_NONE;
+	if (args.np) {
+		if (args.np == np) {
+			dev_err(&pdev->dev, "%s sync own reference\n",
+				np->name);
+			of_node_put(args.np);
+			return -EINVAL;
+		}
+
+		sai->np_sync_provider  = of_get_parent(args.np);
+		if (!sai->np_sync_provider) {
+			dev_err(&pdev->dev, "%s parent node not found\n",
+				np->name);
+			of_node_put(args.np);
+			return -ENODEV;
+		}
+
+		sai->sync = SAI_SYNC_INTERNAL;
+		if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
+			if (!STM_SAI_HAS_EXT_SYNC(sai)) {
+				dev_err(&pdev->dev,
+					"External synchro not supported\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+			sai->sync = SAI_SYNC_EXTERNAL;
+
+			sai->synci = args.args[0];
+			if (sai->synci < 1 ||
+			    (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
+				dev_err(&pdev->dev, "Wrong SAI index\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-a") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_A;
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-b") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_B;
+
+			if (!sai->synco) {
+				dev_err(&pdev->dev, "Unknown SAI sub-block\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+		}
+
+		dev_dbg(&pdev->dev, "%s synchronized with %s\n",
+			pdev->name, args.np->full_name);
+	}
+
+	of_node_put(args.np);
 	sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
 	if (IS_ERR(sai->sai_ck)) {
 		dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Add synchronization support" to the asoc tree
@ 2017-10-21 10:31     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   ASoC: stm32: sai: Add synchronization support

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 5914d285f6b782892a91d6621723fdc41a775b15 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:23 +0200
Subject: [PATCH] ASoC: stm32: sai: Add synchronization support

Add Synchronization support for STM32 SAI.

Signed-off-by: olivier moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai.c     | 160 ++++++++++++++++++++++++++++++++++++++++--
 sound/soc/stm/stm32_sai.h     |  22 +++++-
 sound/soc/stm/stm32_sai_sub.c |  95 +++++++++++++++++++++++++
 3 files changed, 269 insertions(+), 8 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 5fe878ace605..d6f71a3406e9 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/module.h>
@@ -27,6 +28,16 @@
 
 #include "stm32_sai.h"
 
+static LIST_HEAD(sync_providers);
+static DEFINE_MUTEX(sync_mutex);
+
+struct sync_provider {
+	struct list_head link;
+	struct device_node *node;
+	int  (*sync_conf)(void *data, int synco);
+	void *data;
+};
+
 static const struct stm32_sai_conf stm32_sai_conf_f4 = {
 	.version = SAI_STM32F4,
 };
@@ -41,23 +52,143 @@ static const struct of_device_id stm32_sai_ids[] = {
 	{}
 };
 
+static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+{
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_sync_conf_provider(void *data, int synco)
+{
+	struct stm32_sai_data *sai = (struct stm32_sai_data *)data;
+	u32 prev_synco;
+	int ret;
+
+	/* Enable peripheral clock to allow GCR register access */
+	ret = clk_prepare_enable(sai->pclk);
+	if (ret) {
+		dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(&sai->pdev->dev, "Set %s%s as synchro provider\n",
+		sai->pdev->dev.of_node->name,
+		synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+
+	prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base));
+	if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) {
+		dev_err(&sai->pdev->dev, "%s%s already set as sync provider\n",
+			sai->pdev->dev.of_node->name,
+			prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
+		clk_disable_unprepare(sai->pclk);
+		return -EINVAL;
+	}
+
+	writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
+
+	clk_disable_unprepare(sai->pclk);
+
+	return 0;
+}
+
+static int stm32_sai_set_sync_provider(struct device_node *np, int synco)
+{
+	struct sync_provider *provider;
+	int ret;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(provider, &sync_providers, link) {
+		if (provider->node == np) {
+			ret = provider->sync_conf(provider->data, synco);
+			mutex_unlock(&sync_mutex);
+			return ret;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+
+	/* SAI sync provider not found */
+	return -ENODEV;
+}
+
+static int stm32_sai_set_sync(struct stm32_sai_data *sai,
+			      struct device_node *np_provider,
+			      int synco, int synci)
+{
+	int ret;
+
+	/* Configure sync client */
+	stm32_sai_sync_conf_client(sai, synci);
+
+	/* Configure sync provider */
+	ret = stm32_sai_set_sync_provider(np_provider, synco);
+
+	return ret;
+}
+
+static int stm32_sai_sync_add_provider(struct platform_device *pdev,
+				       void *data)
+{
+	struct sync_provider *sp;
+
+	sp = devm_kzalloc(&pdev->dev, sizeof(*sp), GFP_KERNEL);
+	if (!sp)
+		return -ENOMEM;
+
+	sp->node = of_node_get(pdev->dev.of_node);
+	sp->data = data;
+	sp->sync_conf = &stm32_sai_sync_conf_provider;
+
+	mutex_lock(&sync_mutex);
+	list_add(&sp->link, &sync_providers);
+	mutex_unlock(&sync_mutex);
+
+	return 0;
+}
+
+static void stm32_sai_sync_del_provider(struct device_node *np)
+{
+	struct sync_provider *sp;
+
+	mutex_lock(&sync_mutex);
+	list_for_each_entry(sp, &sync_providers, link) {
+		if (sp->node == np) {
+			list_del(&sp->link);
+			of_node_put(sp->node);
+			break;
+		}
+	}
+	mutex_unlock(&sync_mutex);
+}
+
 static int stm32_sai_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct stm32_sai_data *sai;
 	struct reset_control *rst;
 	struct resource *res;
-	void __iomem *base;
 	const struct of_device_id *of_id;
+	int ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	sai->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sai->base))
+		return PTR_ERR(sai->base);
 
 	of_id = of_match_device(stm32_sai_ids, &pdev->dev);
 	if (of_id)
@@ -65,6 +196,14 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	else
 		return -EINVAL;
 
+	if (!STM_SAI_IS_F4(sai)) {
+		sai->pclk = devm_clk_get(&pdev->dev, "pclk");
+		if (IS_ERR(sai->pclk)) {
+			dev_err(&pdev->dev, "missing bus clock pclk\n");
+			return PTR_ERR(sai->pclk);
+		}
+	}
+
 	sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
 	if (IS_ERR(sai->clk_x8k)) {
 		dev_err(&pdev->dev, "missing x8k parent clock\n");
@@ -92,16 +231,27 @@ static int stm32_sai_probe(struct platform_device *pdev)
 		reset_control_deassert(rst);
 	}
 
+	ret = stm32_sai_sync_add_provider(pdev, sai);
+	if (ret < 0)
+		return ret;
+	sai->set_sync = &stm32_sai_set_sync;
+
 	sai->pdev = pdev;
 	platform_set_drvdata(pdev, sai);
 
-	return of_platform_populate(np, NULL, NULL, &pdev->dev);
+	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+	if (ret < 0)
+		stm32_sai_sync_del_provider(np);
+
+	return ret;
 }
 
 static int stm32_sai_remove(struct platform_device *pdev)
 {
 	of_platform_depopulate(&pdev->dev);
 
+	stm32_sai_sync_del_provider(pdev->dev.of_node);
+
 	return 0;
 }
 
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 889974dc62d9..bb062e70de63 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -16,9 +16,11 @@
  * details.
  */
 
+#include <linux/bitfield.h>
+
 /******************** SAI Register Map **************************************/
 
-/* common register */
+/* Global configuration register */
 #define STM_SAI_GCR		0x00
 
 /* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
@@ -37,12 +39,13 @@
 
 /******************** Bit definition for SAI_GCR register *******************/
 #define SAI_GCR_SYNCIN_SHIFT	0
+#define SAI_GCR_SYNCIN_WDTH	2
 #define SAI_GCR_SYNCIN_MASK	GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
-#define SAI_GCR_SYNCIN_SET(x)	((x) << SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_MAX	FIELD_GET(SAI_GCR_SYNCIN_MASK,\
+				SAI_GCR_SYNCIN_MASK)
 
 #define SAI_GCR_SYNCOUT_SHIFT	4
 #define SAI_GCR_SYNCOUT_MASK	GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
-#define SAI_GCR_SYNCOUT_SET(x)	((x) << SAI_GCR_SYNCOUT_SHIFT)
 
 /******************* Bit definition for SAI_XCR1 register *******************/
 #define SAI_XCR1_RX_TX_SHIFT	0
@@ -231,6 +234,12 @@
 #define STM_SAI_IS_F4(ip)	((ip)->conf->version == SAI_STM32F4)
 #define STM_SAI_IS_H7(ip)	((ip)->conf->version == SAI_STM32H7)
 
+enum stm32_sai_syncout {
+	STM_SAI_SYNC_OUT_NONE,
+	STM_SAI_SYNC_OUT_A,
+	STM_SAI_SYNC_OUT_B,
+};
+
 enum stm32_sai_version {
 	SAI_STM32F4,
 	SAI_STM32H7
@@ -247,15 +256,22 @@ struct stm32_sai_conf {
 /**
  * struct stm32_sai_data - private data of SAI instance driver
  * @pdev: device data pointer
+ * @base: common register bank virtual base address
+ * @pclk: SAI bus clock
  * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
  * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
  * @version: SOC version
  * @irq: SAI interrupt line
+ * @set_sync: pointer to synchro mode configuration callback
  */
 struct stm32_sai_data {
 	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *pclk;
 	struct clk *clk_x8k;
 	struct clk *clk_x11k;
 	struct stm32_sai_conf *conf;
 	int irq;
+	int (*set_sync)(struct stm32_sai_data *sai,
+			struct device_node *np_provider, int synco, int synci);
 };
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index fd7dc7760f58..150ad546d8b9 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -55,6 +55,12 @@
 #define STM_SAI_IS_SUB_B(x)	((x)->id == STM_SAI_B_ID)
 #define STM_SAI_BLOCK_NAME(x)	(((x)->id == STM_SAI_A_ID) ? "A" : "B")
 
+#define SAI_SYNC_NONE		0x0
+#define SAI_SYNC_INTERNAL	0x1
+#define SAI_SYNC_EXTERNAL	0x2
+
+#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
+
 /**
  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
  * @pdev: device data pointer
@@ -65,6 +71,7 @@
  * @cpu_dai: DAI runtime data pointer
  * @substream: PCM substream data pointer
  * @pdata: SAI block parent data pointer
+ * @np_sync_provider: synchronization provider node
  * @sai_ck: kernel clock feeding the SAI clock generator
  * @phys_addr: SAI registers physical base address
  * @mclk_rate: SAI block master clock frequency (Hz). set at init
@@ -73,6 +80,8 @@
  * @master: SAI block mode flag. (true=master, false=slave) set at init
  * @fmt: SAI block format. relevant only for custom protocols. set at init
  * @sync: SAI block synchronization mode. (none, internal or external)
+ * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
+ * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
  * @fs_length: frame synchronization length. depends on protocol settings
  * @slots: rx or tx slot number
  * @slot_width: rx or tx slot width in bits
@@ -88,6 +97,7 @@ struct stm32_sai_sub_data {
 	struct snd_soc_dai *cpu_dai;
 	struct snd_pcm_substream *substream;
 	struct stm32_sai_data *pdata;
+	struct device_node *np_sync_provider;
 	struct clk *sai_ck;
 	dma_addr_t phys_addr;
 	unsigned int mclk_rate;
@@ -96,6 +106,8 @@ struct stm32_sai_sub_data {
 	bool master;
 	int fmt;
 	int sync;
+	int synco;
+	int synci;
 	int fs_length;
 	int slots;
 	int slot_width;
@@ -387,6 +399,14 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
 		return -EINVAL;
 	}
+
+	/* Set slave mode if sub-block is synchronized with another SAI */
+	if (sai->sync) {
+		dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
+		cr1 |= SAI_XCR1_SLAVE;
+		sai->master = false;
+	}
+
 	cr1_mask |= SAI_XCR1_SLAVE;
 
 	/* do not generate master by default */
@@ -749,6 +769,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 	if (STM_SAI_IS_CAPTURE(sai))
 		cr1 |= SAI_XCR1_RX_TX;
 
+	/* Configure synchronization */
+	if (sai->sync == SAI_SYNC_EXTERNAL) {
+		/* Configure synchro client and provider */
+		sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+				     sai->synco, sai->synci);
+	}
+
+	cr1_mask |= SAI_XCR1_SYNCEN_MASK;
+	cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
+
 	return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
 }
 
@@ -835,6 +865,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 	struct device_node *np = pdev->dev.of_node;
 	struct resource *res;
 	void __iomem *base;
+	struct of_phandle_args args;
+	int ret;
 
 	if (!np)
 		return -ENODEV;
@@ -868,6 +900,69 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
+	/* Get synchronization property */
+	args.np = NULL;
+	ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
+	if (ret < 0  && ret != -ENOENT) {
+		dev_err(&pdev->dev, "Failed to get st,sync property\n");
+		return ret;
+	}
+
+	sai->sync = SAI_SYNC_NONE;
+	if (args.np) {
+		if (args.np == np) {
+			dev_err(&pdev->dev, "%s sync own reference\n",
+				np->name);
+			of_node_put(args.np);
+			return -EINVAL;
+		}
+
+		sai->np_sync_provider  = of_get_parent(args.np);
+		if (!sai->np_sync_provider) {
+			dev_err(&pdev->dev, "%s parent node not found\n",
+				np->name);
+			of_node_put(args.np);
+			return -ENODEV;
+		}
+
+		sai->sync = SAI_SYNC_INTERNAL;
+		if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
+			if (!STM_SAI_HAS_EXT_SYNC(sai)) {
+				dev_err(&pdev->dev,
+					"External synchro not supported\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+			sai->sync = SAI_SYNC_EXTERNAL;
+
+			sai->synci = args.args[0];
+			if (sai->synci < 1 ||
+			    (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
+				dev_err(&pdev->dev, "Wrong SAI index\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-a") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_A;
+
+			if (of_property_match_string(args.np, "compatible",
+						     "st,stm32-sai-sub-b") >= 0)
+				sai->synco = STM_SAI_SYNC_OUT_B;
+
+			if (!sai->synco) {
+				dev_err(&pdev->dev, "Unknown SAI sub-block\n");
+				of_node_put(args.np);
+				return -EINVAL;
+			}
+		}
+
+		dev_dbg(&pdev->dev, "%s synchronized with %s\n",
+			pdev->name, args.np->full_name);
+	}
+
+	of_node_put(args.np);
 	sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
 	if (IS_ERR(sai->sai_ck)) {
 		dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Remove spurious IRQs on stop" to the asoc tree
  2017-10-19 13:03   ` Olivier Moysan
  (?)
@ 2017-10-21 10:31     ` Mark Brown
  -1 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: Mark Brown, lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan,
	arnaud.pouliquen, benjamin.gaignard, alsa-devel

The patch

   ASoC: stm32: sai: Remove spurious IRQs on stop

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 47a8907d7c73fad81030655f09832fbb4446a2f5 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:21 +0200
Subject: [PATCH] ASoC: stm32: sai: Remove spurious IRQs on stop

Clear IRQ mask on stream stop to avoid spurious IRQs.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai_sub.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 815ef1036199..fd7dc7760f58 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -419,8 +419,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
 	}
 
 	/* Enable ITs */
-	regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
-			   SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
 
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
 			   SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
@@ -693,6 +691,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_STOP:
 		dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
 
+		regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+				   SAI_XIMR_MASK, 0);
+
 		regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 				   SAI_XCR1_SAIEN,
 				   (unsigned int)~SAI_XCR1_SAIEN);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Remove spurious IRQs on stop" to the asoc tree
@ 2017-10-21 10:31     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  Cc: Mark Brown, lgirdwood

The patch

   ASoC: stm32: sai: Remove spurious IRQs on stop

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 47a8907d7c73fad81030655f09832fbb4446a2f5 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:21 +0200
Subject: [PATCH] ASoC: stm32: sai: Remove spurious IRQs on stop

Clear IRQ mask on stream stop to avoid spurious IRQs.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai_sub.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 815ef1036199..fd7dc7760f58 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -419,8 +419,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
 	}
 
 	/* Enable ITs */
-	regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
-			   SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
 
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
 			   SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
@@ -693,6 +691,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_STOP:
 		dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
 
+		regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+				   SAI_XIMR_MASK, 0);
+
 		regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 				   SAI_XCR1_SAIEN,
 				   (unsigned int)~SAI_XCR1_SAIEN);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Remove spurious IRQs on stop" to the asoc tree
@ 2017-10-21 10:31     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   ASoC: stm32: sai: Remove spurious IRQs on stop

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 47a8907d7c73fad81030655f09832fbb4446a2f5 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:21 +0200
Subject: [PATCH] ASoC: stm32: sai: Remove spurious IRQs on stop

Clear IRQ mask on stream stop to avoid spurious IRQs.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai_sub.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 815ef1036199..fd7dc7760f58 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -419,8 +419,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
 	}
 
 	/* Enable ITs */
-	regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
-			   SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
 
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
 			   SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
@@ -693,6 +691,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
 	case SNDRV_PCM_TRIGGER_STOP:
 		dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
 
+		regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+				   SAI_XIMR_MASK, 0);
+
 		regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 				   SAI_XCR1_SAIEN,
 				   (unsigned int)~SAI_XCR1_SAIEN);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: Add synchronization to SAI bindings" to the asoc tree
  2017-10-19 13:03   ` Olivier Moysan
  (?)
@ 2017-10-21 10:31     ` Mark Brown
  -1 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: Mark Brown, lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan,
	arnaud.pouliquen, benjamin.gaignard, alsa-devel

The patch

   ASoC: stm32: Add synchronization to SAI bindings

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 14f0e5f8d97e632695d92f41f2e91d10d8005d47 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:17 +0200
Subject: [PATCH] ASoC: stm32: Add synchronization to SAI bindings

Add synchronization configuration to STM32 SAI bindings.
This patch also adds peripheral clock which is required
to access synchronization register.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index f1c5ae59e7c9..1f9cd7095337 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -10,13 +10,21 @@ Required properties:
   - reg: Base address and size of SAI common register set.
   - clocks: Must contain phandle and clock specifier pairs for each entry
 	in clock-names.
-  - clock-names: Must contain "x8k" and "x11k"
+  - clock-names: Must contain "pclk" "x8k" and "x11k"
+	"pclk": Clock which feeds the peripheral bus interface.
+	        Mandatory for "st,stm32h7-sai" compatible.
+	        Not used for "st,stm32f4-sai" compatible.
 	"x8k": SAI parent clock for sampling rates multiple of 8kHz.
 	"x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
   - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
 
 Optional properties:
   - resets: Reference to a reset controller asserting the SAI
+  - st,sync: specify synchronization mode.
+	By default SAI sub-block is in asynchronous mode.
+	This property sets SAI sub-block as slave of another SAI sub-block.
+	Must contain the phandle and index of the sai sub-block providing
+	the synchronization.
 
 SAI subnodes:
 Two subnodes corresponding to SAI sub-block instances A et B can be defined.
@@ -52,8 +60,8 @@ sai1: sai1@40015800 {
 	#size-cells = <1>;
 	ranges = <0 0x40015800 0x400>;
 	reg = <0x40015800 0x4>;
-	clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
-	clock-names = "x8k", "x11k";
+	clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
+	clock-names = "pclk", "x8k", "x11k";
 	interrupts = <87>;
 
 	sai1a: audio-controller@40015804 {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: Add synchronization to SAI bindings" to the asoc tree
@ 2017-10-21 10:31     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  Cc: Mark Brown, lgirdwood

The patch

   ASoC: stm32: Add synchronization to SAI bindings

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 14f0e5f8d97e632695d92f41f2e91d10d8005d47 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:17 +0200
Subject: [PATCH] ASoC: stm32: Add synchronization to SAI bindings

Add synchronization configuration to STM32 SAI bindings.
This patch also adds peripheral clock which is required
to access synchronization register.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index f1c5ae59e7c9..1f9cd7095337 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -10,13 +10,21 @@ Required properties:
   - reg: Base address and size of SAI common register set.
   - clocks: Must contain phandle and clock specifier pairs for each entry
 	in clock-names.
-  - clock-names: Must contain "x8k" and "x11k"
+  - clock-names: Must contain "pclk" "x8k" and "x11k"
+	"pclk": Clock which feeds the peripheral bus interface.
+	        Mandatory for "st,stm32h7-sai" compatible.
+	        Not used for "st,stm32f4-sai" compatible.
 	"x8k": SAI parent clock for sampling rates multiple of 8kHz.
 	"x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
   - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
 
 Optional properties:
   - resets: Reference to a reset controller asserting the SAI
+  - st,sync: specify synchronization mode.
+	By default SAI sub-block is in asynchronous mode.
+	This property sets SAI sub-block as slave of another SAI sub-block.
+	Must contain the phandle and index of the sai sub-block providing
+	the synchronization.
 
 SAI subnodes:
 Two subnodes corresponding to SAI sub-block instances A et B can be defined.
@@ -52,8 +60,8 @@ sai1: sai1@40015800 {
 	#size-cells = <1>;
 	ranges = <0 0x40015800 0x400>;
 	reg = <0x40015800 0x4>;
-	clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
-	clock-names = "x8k", "x11k";
+	clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
+	clock-names = "pclk", "x8k", "x11k";
 	interrupts = <87>;
 
 	sai1a: audio-controller@40015804 {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: Add synchronization to SAI bindings" to the asoc tree
@ 2017-10-21 10:31     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   ASoC: stm32: Add synchronization to SAI bindings

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 14f0e5f8d97e632695d92f41f2e91d10d8005d47 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:17 +0200
Subject: [PATCH] ASoC: stm32: Add synchronization to SAI bindings

Add synchronization configuration to STM32 SAI bindings.
This patch also adds peripheral clock which is required
to access synchronization register.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
index f1c5ae59e7c9..1f9cd7095337 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -10,13 +10,21 @@ Required properties:
   - reg: Base address and size of SAI common register set.
   - clocks: Must contain phandle and clock specifier pairs for each entry
 	in clock-names.
-  - clock-names: Must contain "x8k" and "x11k"
+  - clock-names: Must contain "pclk" "x8k" and "x11k"
+	"pclk": Clock which feeds the peripheral bus interface.
+	        Mandatory for "st,stm32h7-sai" compatible.
+	        Not used for "st,stm32f4-sai" compatible.
 	"x8k": SAI parent clock for sampling rates multiple of 8kHz.
 	"x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
   - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
 
 Optional properties:
   - resets: Reference to a reset controller asserting the SAI
+  - st,sync: specify synchronization mode.
+	By default SAI sub-block is in asynchronous mode.
+	This property sets SAI sub-block as slave of another SAI sub-block.
+	Must contain the phandle and index of the sai sub-block providing
+	the synchronization.
 
 SAI subnodes:
 Two subnodes corresponding to SAI sub-block instances A et B can be defined.
@@ -52,8 +60,8 @@ sai1: sai1 at 40015800 {
 	#size-cells = <1>;
 	ranges = <0 0x40015800 0x400>;
 	reg = <0x40015800 0x4>;
-	clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
-	clock-names = "x8k", "x11k";
+	clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
+	clock-names = "pclk", "x8k", "x11k";
 	interrupts = <87>;
 
 	sai1a: audio-controller at 40015804 {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Fix get reset controller" to the asoc tree
  2017-10-19 13:03   ` Olivier Moysan
  (?)
@ 2017-10-21 10:32     ` Mark Brown
  -1 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:32 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: Mark Brown, lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan,
	arnaud.pouliquen, benjamin.gaignard, alsa-devel

The patch

   ASoC: stm32: sai: Fix get reset controller

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 3c6f6c53ab4df585639bbe647b45aa81ca54bdd2 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:22 +0200
Subject: [PATCH] ASoC: stm32: sai: Fix get reset controller

Use devm version of reset_control_get function
to manage driver removing properly.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 1258bef4dcb3..5fe878ace605 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	}
 
 	/* reset */
-	rst = reset_control_get_exclusive(&pdev->dev, NULL);
+	rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (!IS_ERR(rst)) {
 		reset_control_assert(rst);
 		udelay(2);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Fix get reset controller" to the asoc tree
@ 2017-10-21 10:32     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:32 UTC (permalink / raw)
  Cc: Mark Brown, lgirdwood

The patch

   ASoC: stm32: sai: Fix get reset controller

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 3c6f6c53ab4df585639bbe647b45aa81ca54bdd2 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:22 +0200
Subject: [PATCH] ASoC: stm32: sai: Fix get reset controller

Use devm version of reset_control_get function
to manage driver removing properly.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 1258bef4dcb3..5fe878ace605 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	}
 
 	/* reset */
-	rst = reset_control_get_exclusive(&pdev->dev, NULL);
+	rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (!IS_ERR(rst)) {
 		reset_control_assert(rst);
 		udelay(2);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: Fix get reset controller" to the asoc tree
@ 2017-10-21 10:32     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:32 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   ASoC: stm32: sai: Fix get reset controller

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 3c6f6c53ab4df585639bbe647b45aa81ca54bdd2 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:22 +0200
Subject: [PATCH] ASoC: stm32: sai: Fix get reset controller

Use devm version of reset_control_get function
to manage driver removing properly.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 1258bef4dcb3..5fe878ace605 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev)
 	}
 
 	/* reset */
-	rst = reset_control_get_exclusive(&pdev->dev, NULL);
+	rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (!IS_ERR(rst)) {
 		reset_control_assert(rst);
 		udelay(2);
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: fix stop management in isr" to the asoc tree
  2017-10-19 13:03   ` Olivier Moysan
  (?)
@ 2017-10-21 10:32     ` Mark Brown
  -1 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:32 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: Mark Brown, lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
	alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
	linux-arm-kernel, kernel, linux-kernel, olivier.moysan,
	arnaud.pouliquen, benjamin.gaignard, alsa-devel

The patch

   ASoC: stm32: sai: fix stop management in isr

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From d807cdfb48c4d925b269f5b0f818864766e17389 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:20 +0200
Subject: [PATCH] ASoC: stm32: sai: fix stop management in isr

Add check on substream validity.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 90d439613899..5e66bf310351 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -184,7 +184,6 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
 static irqreturn_t stm32_sai_isr(int irq, void *devid)
 {
 	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
-	struct snd_pcm_substream *substream = sai->substream;
 	struct platform_device *pdev = sai->pdev;
 	unsigned int sr, imr, flags;
 	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
 			   SAI_XCLRFR_MASK);
 
+	if (!sai->substream) {
+		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
+		return IRQ_NONE;
+	}
+
 	if (flags & SAI_XIMR_OVRUDRIE) {
 		dev_err(&pdev->dev, "IRQ %s\n",
 			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	}
 
 	if (status != SNDRV_PCM_STATE_RUNNING) {
-		snd_pcm_stream_lock(substream);
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		snd_pcm_stream_unlock(substream);
+		snd_pcm_stream_lock(sai->substream);
+		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock(sai->substream);
 	}
 
 	return IRQ_HANDLED;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: fix stop management in isr" to the asoc tree
@ 2017-10-21 10:32     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:32 UTC (permalink / raw)
  Cc: Mark Brown, lgirdwood

The patch

   ASoC: stm32: sai: fix stop management in isr

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From d807cdfb48c4d925b269f5b0f818864766e17389 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:20 +0200
Subject: [PATCH] ASoC: stm32: sai: fix stop management in isr

Add check on substream validity.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 90d439613899..5e66bf310351 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -184,7 +184,6 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
 static irqreturn_t stm32_sai_isr(int irq, void *devid)
 {
 	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
-	struct snd_pcm_substream *substream = sai->substream;
 	struct platform_device *pdev = sai->pdev;
 	unsigned int sr, imr, flags;
 	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
 			   SAI_XCLRFR_MASK);
 
+	if (!sai->substream) {
+		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
+		return IRQ_NONE;
+	}
+
 	if (flags & SAI_XIMR_OVRUDRIE) {
 		dev_err(&pdev->dev, "IRQ %s\n",
 			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	}
 
 	if (status != SNDRV_PCM_STATE_RUNNING) {
-		snd_pcm_stream_lock(substream);
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		snd_pcm_stream_unlock(substream);
+		snd_pcm_stream_lock(sai->substream);
+		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock(sai->substream);
 	}
 
 	return IRQ_HANDLED;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Applied "ASoC: stm32: sai: fix stop management in isr" to the asoc tree
@ 2017-10-21 10:32     ` Mark Brown
  0 siblings, 0 replies; 51+ messages in thread
From: Mark Brown @ 2017-10-21 10:32 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   ASoC: stm32: sai: fix stop management in isr

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From d807cdfb48c4d925b269f5b0f818864766e17389 Mon Sep 17 00:00:00 2001
From: Olivier Moysan <olivier.moysan@st.com>
Date: Thu, 19 Oct 2017 15:03:20 +0200
Subject: [PATCH] ASoC: stm32: sai: fix stop management in isr

Add check on substream validity.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 90d439613899..5e66bf310351 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -184,7 +184,6 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
 static irqreturn_t stm32_sai_isr(int irq, void *devid)
 {
 	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
-	struct snd_pcm_substream *substream = sai->substream;
 	struct platform_device *pdev = sai->pdev;
 	unsigned int sr, imr, flags;
 	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
@@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
 			   SAI_XCLRFR_MASK);
 
+	if (!sai->substream) {
+		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
+		return IRQ_NONE;
+	}
+
 	if (flags & SAI_XIMR_OVRUDRIE) {
 		dev_err(&pdev->dev, "IRQ %s\n",
 			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
@@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
 	}
 
 	if (status != SNDRV_PCM_STATE_RUNNING) {
-		snd_pcm_stream_lock(substream);
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-		snd_pcm_stream_unlock(substream);
+		snd_pcm_stream_lock(sai->substream);
+		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
+		snd_pcm_stream_unlock(sai->substream);
 	}
 
 	return IRQ_HANDLED;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
  2017-10-19 13:03   ` Olivier Moysan
  (?)
@ 2017-10-26 15:32     ` Takashi Iwai
  -1 siblings, 0 replies; 51+ messages in thread
From: Takashi Iwai @ 2017-10-26 15:32 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: alsa-devel, mark.rutland, lgirdwood, mcoquelin.stm32, broonie,
	robh, linux-arm-kernel, perex, alexandre.torgue, kernel,
	devicetree, linux-kernel, arnaud.pouliquen, benjamin.gaignard

On Thu, 19 Oct 2017 15:03:20 +0200,
Olivier Moysan wrote:
> 
> Add check on substream validity.
> 
> Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
> ---
>  sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
> index 2af397d..815ef10 100644
> --- a/sound/soc/stm/stm32_sai_sub.c
> +++ b/sound/soc/stm/stm32_sai_sub.c
> @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
>  static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  {
>  	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
> -	struct snd_pcm_substream *substream = sai->substream;
>  	struct platform_device *pdev = sai->pdev;
>  	unsigned int sr, imr, flags;
>  	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
> @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
>  			   SAI_XCLRFR_MASK);
>  
> +	if (!sai->substream) {
> +		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
> +		return IRQ_NONE;
> +	}
> +
>  	if (flags & SAI_XIMR_OVRUDRIE) {
>  		dev_err(&pdev->dev, "IRQ %s\n",
>  			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
> @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  	}
>  
>  	if (status != SNDRV_PCM_STATE_RUNNING) {
> -		snd_pcm_stream_lock(substream);
> -		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
> -		snd_pcm_stream_unlock(substream);
> +		snd_pcm_stream_lock(sai->substream);
> +		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
> +		snd_pcm_stream_unlock(sai->substream);

Actually changing to sai->substream opens a race, so this chunk is a
bad move, at least.  We have no protection of sai->substream in this
context, thus it can hit a NULL dereference...


thanks,

Takashi

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-10-26 15:32     ` Takashi Iwai
  0 siblings, 0 replies; 51+ messages in thread
From: Takashi Iwai @ 2017-10-26 15:32 UTC (permalink / raw)
  To: Olivier Moysan
  Cc: alsa-devel, mark.rutland, lgirdwood, mcoquelin.stm32, broonie,
	robh, linux-arm-kernel, perex, alexandre.torgue, kernel,
	devicetree, linux-kernel, arnaud.pouliquen, benjamin.gaignard

On Thu, 19 Oct 2017 15:03:20 +0200,
Olivier Moysan wrote:
> 
> Add check on substream validity.
> 
> Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
> ---
>  sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
> index 2af397d..815ef10 100644
> --- a/sound/soc/stm/stm32_sai_sub.c
> +++ b/sound/soc/stm/stm32_sai_sub.c
> @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
>  static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  {
>  	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
> -	struct snd_pcm_substream *substream = sai->substream;
>  	struct platform_device *pdev = sai->pdev;
>  	unsigned int sr, imr, flags;
>  	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
> @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
>  			   SAI_XCLRFR_MASK);
>  
> +	if (!sai->substream) {
> +		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
> +		return IRQ_NONE;
> +	}
> +
>  	if (flags & SAI_XIMR_OVRUDRIE) {
>  		dev_err(&pdev->dev, "IRQ %s\n",
>  			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
> @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  	}
>  
>  	if (status != SNDRV_PCM_STATE_RUNNING) {
> -		snd_pcm_stream_lock(substream);
> -		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
> -		snd_pcm_stream_unlock(substream);
> +		snd_pcm_stream_lock(sai->substream);
> +		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
> +		snd_pcm_stream_unlock(sai->substream);

Actually changing to sai->substream opens a race, so this chunk is a
bad move, at least.  We have no protection of sai->substream in this
context, thus it can hit a NULL dereference...


thanks,

Takashi

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-10-26 15:32     ` Takashi Iwai
  0 siblings, 0 replies; 51+ messages in thread
From: Takashi Iwai @ 2017-10-26 15:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 19 Oct 2017 15:03:20 +0200,
Olivier Moysan wrote:
> 
> Add check on substream validity.
> 
> Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
> ---
>  sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
> index 2af397d..815ef10 100644
> --- a/sound/soc/stm/stm32_sai_sub.c
> +++ b/sound/soc/stm/stm32_sai_sub.c
> @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
>  static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  {
>  	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
> -	struct snd_pcm_substream *substream = sai->substream;
>  	struct platform_device *pdev = sai->pdev;
>  	unsigned int sr, imr, flags;
>  	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
> @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
>  			   SAI_XCLRFR_MASK);
>  
> +	if (!sai->substream) {
> +		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
> +		return IRQ_NONE;
> +	}
> +
>  	if (flags & SAI_XIMR_OVRUDRIE) {
>  		dev_err(&pdev->dev, "IRQ %s\n",
>  			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
> @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>  	}
>  
>  	if (status != SNDRV_PCM_STATE_RUNNING) {
> -		snd_pcm_stream_lock(substream);
> -		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
> -		snd_pcm_stream_unlock(substream);
> +		snd_pcm_stream_lock(sai->substream);
> +		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
> +		snd_pcm_stream_unlock(sai->substream);

Actually changing to sai->substream opens a race, so this chunk is a
bad move, at least.  We have no protection of sai->substream in this
context, thus it can hit a NULL dereference...


thanks,

Takashi

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
  2017-10-26 15:32     ` Takashi Iwai
  (?)
@ 2017-11-02 16:38       ` Olivier MOYSAN
  -1 siblings, 0 replies; 51+ messages in thread
From: Olivier MOYSAN @ 2017-11-02 16:38 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: alsa-devel, mark.rutland, lgirdwood, mcoquelin.stm32, broonie,
	robh, linux-arm-kernel, perex, Alexandre TORGUE, kernel,
	devicetree, linux-kernel, Arnaud POULIQUEN, Benjamin GAIGNARD

Hello Takashi,

Sorry for late answer. I was OoO.
Ok, I will add a protection on sai->substream accesses.

Best regards
Olivier


On 10/26/2017 05:32 PM, Takashi Iwai wrote:
> On Thu, 19 Oct 2017 15:03:20 +0200,
> Olivier Moysan wrote:
>>
>> Add check on substream validity.
>>
>> Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
>> ---
>>   sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
>>   1 file changed, 8 insertions(+), 4 deletions(-)
>>
>> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
>> index 2af397d..815ef10 100644
>> --- a/sound/soc/stm/stm32_sai_sub.c
>> +++ b/sound/soc/stm/stm32_sai_sub.c
>> @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
>>   static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   {
>>   	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
>> -	struct snd_pcm_substream *substream = sai->substream;
>>   	struct platform_device *pdev = sai->pdev;
>>   	unsigned int sr, imr, flags;
>>   	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
>> @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
>>   			   SAI_XCLRFR_MASK);
>>   
>> +	if (!sai->substream) {
>> +		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
>> +		return IRQ_NONE;
>> +	}
>> +
>>   	if (flags & SAI_XIMR_OVRUDRIE) {
>>   		dev_err(&pdev->dev, "IRQ %s\n",
>>   			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
>> @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   	}
>>   
>>   	if (status != SNDRV_PCM_STATE_RUNNING) {
>> -		snd_pcm_stream_lock(substream);
>> -		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
>> -		snd_pcm_stream_unlock(substream);
>> +		snd_pcm_stream_lock(sai->substream);
>> +		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
>> +		snd_pcm_stream_unlock(sai->substream);
> 
> Actually changing to sai->substream opens a race, so this chunk is a
> bad move, at least.  We have no protection of sai->substream in this
> context, thus it can hit a NULL dereference...
> 
> 
> thanks,
> 
> Takashi
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-11-02 16:38       ` Olivier MOYSAN
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier MOYSAN @ 2017-11-02 16:38 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: mark.rutland, robh, alsa-devel, Alexandre TORGUE, devicetree,
	linux-kernel, Arnaud POULIQUEN, lgirdwood, broonie,
	mcoquelin.stm32, Benjamin GAIGNARD, linux-arm-kernel, kernel

Hello Takashi,

Sorry for late answer. I was OoO.
Ok, I will add a protection on sai->substream accesses.

Best regards
Olivier


On 10/26/2017 05:32 PM, Takashi Iwai wrote:
> On Thu, 19 Oct 2017 15:03:20 +0200,
> Olivier Moysan wrote:
>>
>> Add check on substream validity.
>>
>> Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
>> ---
>>   sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
>>   1 file changed, 8 insertions(+), 4 deletions(-)
>>
>> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
>> index 2af397d..815ef10 100644
>> --- a/sound/soc/stm/stm32_sai_sub.c
>> +++ b/sound/soc/stm/stm32_sai_sub.c
>> @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
>>   static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   {
>>   	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
>> -	struct snd_pcm_substream *substream = sai->substream;
>>   	struct platform_device *pdev = sai->pdev;
>>   	unsigned int sr, imr, flags;
>>   	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
>> @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
>>   			   SAI_XCLRFR_MASK);
>>   
>> +	if (!sai->substream) {
>> +		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
>> +		return IRQ_NONE;
>> +	}
>> +
>>   	if (flags & SAI_XIMR_OVRUDRIE) {
>>   		dev_err(&pdev->dev, "IRQ %s\n",
>>   			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
>> @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   	}
>>   
>>   	if (status != SNDRV_PCM_STATE_RUNNING) {
>> -		snd_pcm_stream_lock(substream);
>> -		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
>> -		snd_pcm_stream_unlock(substream);
>> +		snd_pcm_stream_lock(sai->substream);
>> +		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
>> +		snd_pcm_stream_unlock(sai->substream);
> 
> Actually changing to sai->substream opens a race, so this chunk is a
> bad move, at least.  We have no protection of sai->substream in this
> context, thus it can hit a NULL dereference...
> 
> 
> thanks,
> 
> Takashi
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
@ 2017-11-02 16:38       ` Olivier MOYSAN
  0 siblings, 0 replies; 51+ messages in thread
From: Olivier MOYSAN @ 2017-11-02 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Takashi,

Sorry for late answer. I was OoO.
Ok, I will add a protection on sai->substream accesses.

Best regards
Olivier


On 10/26/2017 05:32 PM, Takashi Iwai wrote:
> On Thu, 19 Oct 2017 15:03:20 +0200,
> Olivier Moysan wrote:
>>
>> Add check on substream validity.
>>
>> Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
>> ---
>>   sound/soc/stm/stm32_sai_sub.c | 12 ++++++++----
>>   1 file changed, 8 insertions(+), 4 deletions(-)
>>
>> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
>> index 2af397d..815ef10 100644
>> --- a/sound/soc/stm/stm32_sai_sub.c
>> +++ b/sound/soc/stm/stm32_sai_sub.c
>> @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
>>   static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   {
>>   	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
>> -	struct snd_pcm_substream *substream = sai->substream;
>>   	struct platform_device *pdev = sai->pdev;
>>   	unsigned int sr, imr, flags;
>>   	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
>> @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
>>   			   SAI_XCLRFR_MASK);
>>   
>> +	if (!sai->substream) {
>> +		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
>> +		return IRQ_NONE;
>> +	}
>> +
>>   	if (flags & SAI_XIMR_OVRUDRIE) {
>>   		dev_err(&pdev->dev, "IRQ %s\n",
>>   			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
>> @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
>>   	}
>>   
>>   	if (status != SNDRV_PCM_STATE_RUNNING) {
>> -		snd_pcm_stream_lock(substream);
>> -		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
>> -		snd_pcm_stream_unlock(substream);
>> +		snd_pcm_stream_lock(sai->substream);
>> +		snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
>> +		snd_pcm_stream_unlock(sai->substream);
> 
> Actually changing to sai->substream opens a race, so this chunk is a
> bad move, at least.  We have no protection of sai->substream in this
> context, thus it can hit a NULL dereference...
> 
> 
> thanks,
> 
> Takashi
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2017-11-02 16:41 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-19 13:03 [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support Olivier Moysan
2017-10-19 13:03 ` Olivier Moysan
2017-10-19 13:03 ` Olivier Moysan
2017-10-19 13:03 ` [INTERNAL][PATCH 1/7] ASoC: stm32: Add synchronization to SAI bindings Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-21 10:31   ` Applied "ASoC: stm32: Add synchronization to SAI bindings" to the asoc tree Mark Brown
2017-10-21 10:31     ` Mark Brown
2017-10-21 10:31     ` Mark Brown
2017-10-19 13:03 ` [INTERNAL][PATCH 2/7] ASoC: stm32: sai: Move static settings to DAI init Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03 ` [INTERNAL][PATCH 3/7] ASoC: stm32: sai: Fix DMA burst size Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03 ` [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-21 10:16   ` Mark Brown
2017-10-21 10:16     ` Mark Brown
2017-10-21 10:16     ` Mark Brown
2017-10-21 10:32   ` Applied "ASoC: stm32: sai: fix stop management in isr" to the asoc tree Mark Brown
2017-10-21 10:32     ` Mark Brown
2017-10-21 10:32     ` Mark Brown
2017-10-26 15:32   ` [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr Takashi Iwai
2017-10-26 15:32     ` Takashi Iwai
2017-10-26 15:32     ` Takashi Iwai
2017-11-02 16:38     ` Olivier MOYSAN
2017-11-02 16:38       ` Olivier MOYSAN
2017-11-02 16:38       ` Olivier MOYSAN
2017-10-19 13:03 ` [INTERNAL][PATCH 5/7] ASoC: stm32: sai: Remove spurious IRQs on stop Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-21 10:31   ` Applied "ASoC: stm32: sai: Remove spurious IRQs on stop" to the asoc tree Mark Brown
2017-10-21 10:31     ` Mark Brown
2017-10-21 10:31     ` Mark Brown
2017-10-19 13:03 ` [INTERNAL][PATCH 6/7] ASoC: stm32: sai: Fix get reset controller Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-21 10:32   ` Applied "ASoC: stm32: sai: Fix get reset controller" to the asoc tree Mark Brown
2017-10-21 10:32     ` Mark Brown
2017-10-21 10:32     ` Mark Brown
2017-10-19 13:03 ` [INTERNAL][PATCH 7/7] ASoC: stm32: sai: Add synchronization support Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-19 13:03   ` Olivier Moysan
2017-10-21 10:31   ` Applied "ASoC: stm32: sai: Add synchronization support" to the asoc tree Mark Brown
2017-10-21 10:31     ` Mark Brown
2017-10-21 10:31     ` Mark Brown
2017-10-19 13:27 ` [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support Olivier MOYSAN
2017-10-19 13:27   ` Olivier MOYSAN
2017-10-19 13:27   ` Olivier MOYSAN

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.