[RESEND PATCH 2/2] ASoC: stm32: i2s: add master clock provider

2021-02-05 Thread Olivier Moysan
From: Olivier Moysan 

Add master clock generation support in STM32 I2S driver.
The master clock provided by I2S can be used to feed a codec.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 310 --
 1 file changed, 266 insertions(+), 44 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 7c4d63c33f15..7d1672cf78cc 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -8,6 +8,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -196,6 +197,9 @@ enum i2s_datlen {
 #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER)
 #define STM32_I2S_IS_SLAVE(x)  ((x)->ms_flg == I2S_MS_SLAVE)
 
+#define STM32_I2S_NAME_LEN 32
+#define STM32_I2S_RATE_11K 11025
+
 /**
  * struct stm32_i2s_data - private data of I2S
  * @regmap_conf: I2S register map configuration pointer
@@ -206,6 +210,7 @@ enum i2s_datlen {
  * @dma_data_rx: dma configuration data for tx channel
  * @substream: PCM substream data pointer
  * @i2sclk: kernel clock feeding the I2S clock generator
+ * @i2smclk: master clock from I2S mclk provider
  * @pclk: peripheral clock driving bus interface
  * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz
  * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz
@@ -215,6 +220,9 @@ enum i2s_datlen {
  * @irq_lock: prevent race condition with IRQ
  * @mclk_rate: master clock frequency (Hz)
  * @fmt: DAI protocol
+ * @divider: prescaler division ratio
+ * @div: prescaler div field
+ * @odd: prescaler odd field
  * @refcount: keep count of opened streams on I2S
  * @ms_flg: master mode flag.
  */
@@ -227,6 +235,7 @@ struct stm32_i2s_data {
struct snd_dmaengine_dai_dma_data dma_data_rx;
struct snd_pcm_substream *substream;
struct clk *i2sclk;
+   struct clk *i2smclk;
struct clk *pclk;
struct clk *x8kclk;
struct clk *x11kclk;
@@ -236,10 +245,210 @@ struct stm32_i2s_data {
spinlock_t irq_lock; /* used to prevent race condition with IRQ */
unsigned int mclk_rate;
unsigned int fmt;
+   unsigned int divider;
+   unsigned int div;
+   bool odd;
int refcount;
int ms_flg;
 };
 
+struct stm32_i2smclk_data {
+   struct clk_hw hw;
+   unsigned long freq;
+   struct stm32_i2s_data *i2s_data;
+};
+
+#define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw)
+
+static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s,
+ unsigned long input_rate,
+ unsigned long output_rate)
+{
+   unsigned int ratio, div, divider = 1;
+   bool odd;
+
+   ratio = DIV_ROUND_CLOSEST(input_rate, output_rate);
+
+   /* Check the parity of the divider */
+   odd = ratio & 0x1;
+
+   /* Compute the div prescaler */
+   div = ratio >> 1;
+
+   /* If div is 0 actual divider is 1 */
+   if (div) {
+   divider = ((2 * div) + odd);
+   dev_dbg(>pdev->dev, "Divider: 2*%d(div)+%d(odd) = %d\n",
+   div, odd, divider);
+   }
+
+   /* Division by three is not allowed by I2S prescaler */
+   if ((div == 1 && odd) || div > I2S_CGFR_I2SDIV_MAX) {
+   dev_err(>pdev->dev, "Wrong divider setting\n");
+   return -EINVAL;
+   }
+
+   if (input_rate % divider)
+   dev_dbg(>pdev->dev,
+   "Rate not accurate. requested (%ld), actual (%ld)\n",
+   output_rate, input_rate / divider);
+
+   i2s->div = div;
+   i2s->odd = odd;
+   i2s->divider = divider;
+
+   return 0;
+}
+
+static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s)
+{
+   u32 cgfr, cgfr_mask;
+
+   cgfr = I2S_CGFR_I2SDIV_SET(i2s->div) | (i2s->odd << I2S_CGFR_ODD_SHIFT);
+   cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD;
+
+   return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+ cgfr_mask, cgfr);
+}
+
+static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s,
+ unsigned int rate)
+{
+   struct platform_device *pdev = i2s->pdev;
+   struct clk *parent_clk;
+   int ret;
+
+   if (!(rate % STM32_I2S_RATE_11K))
+   parent_clk = i2s->x11kclk;
+   else
+   parent_clk = i2s->x8kclk;
+
+   ret = clk_set_parent(i2s->i2sclk, parent_clk);
+   if (ret)
+   dev_err(>dev,
+   "Error %d setting i2sclk parent clock\n", ret);
+
+   return ret;
+}
+
+static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate,
+unsigned long *prate)
+{
+   struct stm32_i2smclk_data *mclk = to

[RESEND PATCH 1/2] ASoC: dt-bindings: add mclk provider support to stm32 i2s

2021-02-05 Thread Olivier Moysan
From: Olivier Moysan 

Add master clock provider support to STM32 I2S.

Reviewed-by: Rob Herring 
Signed-off-by: Olivier Moysan 
---
 Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml | 4 
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml 
b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
index f32410890589..6feb5a09c184 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
@@ -54,6 +54,10 @@ properties:
   resets:
 maxItems: 1
 
+  "#clock-cells":
+description: Configure the I2S device as MCLK clock provider.
+const: 0
+
 required:
   - compatible
   - "#sound-dai-cells"
-- 
2.17.1



[RESEND PATCH 0/2] ASoC: stm32: i2s: add master clock provider

2021-02-05 Thread Olivier Moysan
Add master clock generation support in STM32 I2S driver.
Resend of patch https://lkml.org/lkml/2020/9/11/264

Olivier Moysan (2):
  ASoC: dt-bindings: add mclk provider support to stm32 i2s
  ASoC: stm32: i2s: add master clock provider

 .../bindings/sound/st,stm32-i2s.yaml  |   4 +
 sound/soc/stm/stm32_i2s.c | 310 +++---
 2 files changed, 270 insertions(+), 44 deletions(-)

-- 
2.17.1



Re: [PATCH v2 0/2] ARM: multi_v7_defconfig: enable dfsdm and spdifrx support

2020-11-26 Thread Olivier MOYSAN
Hi Alex

On 11/26/20 12:25 PM, Alexandre Torgue wrote:
> Hi Olivier
> 
> On 11/20/20 10:15 AM, Olivier Moysan wrote:
>> Add STM32 SPDIFRX and DFSDM audio support to multi_v7_defconfig
>>
>> Change in v2:
>> - Add targeted SoC in commit message for DFSDM config
>>
>> Olivier Moysan (2):
>>    ARM: multi_v7_defconfig: enable spdifrx support
>>    ARM: multi_v7_defconfig: enable dfsdm audio support
>>
>>   arch/arm/configs/multi_v7_defconfig | 2 ++
>>   1 file changed, 2 insertions(+)
>>
> 
> Targeted platform (STM32) should be added in the commit title for both 
> patches as you enable STM32 dfsdm and STM32 spdifrx support. No ?
> 
> If you agree, I'll add it during merge. No need to send a v3.
> 
> Regards
> Alex

It's okay for me.

BRs
Olivier

[PATCH v2 1/2] ARM: multi_v7_defconfig: enable spdifrx support

2020-11-20 Thread Olivier Moysan
Add STM32 SPDIFRX support by enabling CONFIG_SND_SOC_STM32_SPDIFRX
as module.

Signed-off-by: Olivier Moysan 
Reviewed-by: Krzysztof Kozlowski 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 1fff2591e434..b30a3bc6762b 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -742,6 +742,7 @@ CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_STI=m
 CONFIG_SND_SOC_STM32_SAI=m
 CONFIG_SND_SOC_STM32_I2S=m
+CONFIG_SND_SOC_STM32_SPDIFRX=m
 CONFIG_SND_SUN4I_CODEC=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA20_I2S=m
-- 
2.17.1



[PATCH v2 2/2] ARM: multi_v7_defconfig: enable dfsdm audio support

2020-11-20 Thread Olivier Moysan
Add STM32 DFSDM audio support by enabling CONFIG_SND_SOC_STM32_DFSDM
as module.

Signed-off-by: Olivier Moysan 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index b30a3bc6762b..083d5f4450f4 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -743,6 +743,7 @@ CONFIG_SND_SOC_STI=m
 CONFIG_SND_SOC_STM32_SAI=m
 CONFIG_SND_SOC_STM32_I2S=m
 CONFIG_SND_SOC_STM32_SPDIFRX=m
+CONFIG_SND_SOC_STM32_DFSDM=m
 CONFIG_SND_SUN4I_CODEC=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA20_I2S=m
-- 
2.17.1



[PATCH v2 0/2] ARM: multi_v7_defconfig: enable dfsdm and spdifrx support

2020-11-20 Thread Olivier Moysan
Add STM32 SPDIFRX and DFSDM audio support to multi_v7_defconfig

Change in v2:
- Add targeted SoC in commit message for DFSDM config

Olivier Moysan (2):
  ARM: multi_v7_defconfig: enable spdifrx support
  ARM: multi_v7_defconfig: enable dfsdm audio support

 arch/arm/configs/multi_v7_defconfig | 2 ++
 1 file changed, 2 insertions(+)

-- 
2.17.1



[PATCH 2/2] ARM: multi_v7_defconfig: enable dfsdm audio support

2020-11-18 Thread Olivier Moysan
Add DFSDM audio support by enabling CONFIG_SND_SOC_STM32_DFSDM
as module.

Signed-off-by: Olivier Moysan 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index b30a3bc6762b..083d5f4450f4 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -743,6 +743,7 @@ CONFIG_SND_SOC_STI=m
 CONFIG_SND_SOC_STM32_SAI=m
 CONFIG_SND_SOC_STM32_I2S=m
 CONFIG_SND_SOC_STM32_SPDIFRX=m
+CONFIG_SND_SOC_STM32_DFSDM=m
 CONFIG_SND_SUN4I_CODEC=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA20_I2S=m
-- 
2.17.1



[PATCH 1/2] ARM: multi_v7_defconfig: enable spdifrx support

2020-11-18 Thread Olivier Moysan
Add STM32 SPDIFRX support by enabling CONFIG_SND_SOC_STM32_SPDIFRX
as module.

Signed-off-by: Olivier Moysan 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 1fff2591e434..b30a3bc6762b 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -742,6 +742,7 @@ CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_STI=m
 CONFIG_SND_SOC_STM32_SAI=m
 CONFIG_SND_SOC_STM32_I2S=m
+CONFIG_SND_SOC_STM32_SPDIFRX=m
 CONFIG_SND_SUN4I_CODEC=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA20_I2S=m
-- 
2.17.1



[PATCH 0/2] ARM: multi_v7_defconfig: enable dfsdm and spdifrx support

2020-11-18 Thread Olivier Moysan
Add STM32 SPDIFRX and DFSDM audio support to multi_v7_defconfig

Olivier Moysan (2):
  ARM: multi_v7_defconfig: enable spdifrx support
  ARM: multi_v7_defconfig: enable dfsdm audio support

 arch/arm/configs/multi_v7_defconfig | 2 ++
 1 file changed, 2 insertions(+)

-- 
2.17.1



[PATCH] iio: adc: stm32-adc: dma transfers cleanup

2020-11-05 Thread Olivier Moysan
- Remove processing related to DMA in irq handler as this
data transfer is managed directly in DMA callback.
- Update comment in stm32_adc_set_watermark() function.

Signed-off-by: Olivier Moysan 
---
 drivers/iio/adc/stm32-adc.c | 29 ++---
 1 file changed, 6 insertions(+), 23 deletions(-)

diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index b3f31f147347..08be826f1462 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -1310,7 +1310,7 @@ static int stm32_adc_set_watermark(struct iio_dev 
*indio_dev, unsigned int val)
 * dma cyclic transfers are used, buffer is split into two periods.
 * There should be :
 * - always one buffer (period) dma is working on
-* - one buffer (period) driver can push with iio_trigger_poll().
+* - one buffer (period) driver can push data.
 */
watermark = min(watermark, val * (unsigned)(sizeof(u16)));
adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv);
@@ -1573,31 +1573,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, 
void *p)
 
dev_dbg(_dev->dev, "%s bufi=%d\n", __func__, adc->bufi);
 
-   if (!adc->dma_chan) {
-   /* reset buffer index */
-   adc->bufi = 0;
-   iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
-  pf->timestamp);
-   } else {
-   int residue = stm32_adc_dma_residue(adc);
-
-   while (residue >= indio_dev->scan_bytes) {
-   u16 *buffer = (u16 *)>rx_buf[adc->bufi];
-
-   iio_push_to_buffers_with_timestamp(indio_dev, buffer,
-  pf->timestamp);
-   residue -= indio_dev->scan_bytes;
-   adc->bufi += indio_dev->scan_bytes;
-   if (adc->bufi >= adc->rx_buf_sz)
-   adc->bufi = 0;
-   }
-   }
-
+   /* reset buffer index */
+   adc->bufi = 0;
+   iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
+  pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
 
/* re-enable eoc irq */
-   if (!adc->dma_chan)
-   stm32_adc_conv_irq_enable(adc);
+   stm32_adc_conv_irq_enable(adc);
 
return IRQ_HANDLED;
 }
-- 
2.17.1



Re: [PATCH 0/2] ASoC: stm32: i2s: add master clock provider

2020-11-03 Thread Olivier MOYSAN
Hi Mark,

Gentle reminder on this series, as it seems that there was no update 
since Rob's "reviewed-by" for dt bindings, on 11/09.

BRs
Olivier

On 9/11/20 11:19 AM, Olivier Moysan wrote:
> Add master clock generation support in STM32 I2S driver.
> 
> Olivier Moysan (2):
>ASoC: dt-bindings: add mclk provider support to stm32 i2s
>ASoC: stm32: i2s: add master clock provider
> 
>   .../bindings/sound/st,stm32-i2s.yaml  |   4 +
>   sound/soc/stm/stm32_i2s.c | 310 +++---
>   2 files changed, 270 insertions(+), 44 deletions(-)
> 

[PATCH 1/1] iio: adc: stm32-adc: fix a regression when using dma and irq

2020-10-21 Thread Olivier Moysan
Since overrun interrupt support has been added, there's a regression when
two ADCs are used at the same time, with:
- an ADC configured to use IRQs. EOCIE bit is set. The handler is normally
  called in this case.
- an ADC configured to use DMA. EOCIE bit isn't set. EOC triggers the DMA
  request. It's then automatically cleared by DMA read. But the handler
  gets called due to status bit is temporarily set (IRQ triggered by the
  other ADC).

This is a regression as similar issue had been fixed earlier by
commit dcb10920179a ("iio: adc: stm32-adc:
fix a race when using several adcs with dma and irq").
Issue is that stm32_adc_eoc_enabled() returns non-zero value (always)
since OVR bit has been added and enabled for both DMA and IRQ case.

Remove OVR mask in IER register, and rely only on CSR status for overrun.
To avoid subsequent calls to interrupt routine on overrun, CSR OVR bit has
to be cleared. CSR OVR bit cannot be cleared directly by software.
To do this ADC must be stopped first, and OVR bit in ADC ISR has
to be cleared.
Also add a check in ADC IRQ handler to report spurious IRQs.

Fixes: cc06e67d8fa5 ("iio: adc: stm32-adc: Add check on overrun interrupt")

Signed-off-by: Olivier Moysan 
Signed-off-by: Fabrice Gasnier 
---
 drivers/iio/adc/stm32-adc-core.c | 41 +++---
 drivers/iio/adc/stm32-adc.c  | 50 ++--
 2 files changed, 65 insertions(+), 26 deletions(-)

diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index cd870c089182..a83199b212a4 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -41,18 +41,16 @@
  * struct stm32_adc_common_regs - stm32 common registers
  * @csr:   common status register offset
  * @ccr:   common control register offset
- * @eoc1_msk:  adc1 end of conversion flag in @csr
- * @eoc2_msk:  adc2 end of conversion flag in @csr
- * @eoc3_msk:  adc3 end of conversion flag in @csr
+ * @eoc_msk:array of eoc (end of conversion flag) masks in csr for adc1..n
+ * @ovr_msk:array of ovr (overrun flag) masks in csr for adc1..n
  * @ier:   interrupt enable register offset for each adc
  * @eocie_msk: end of conversion interrupt enable mask in @ier
  */
 struct stm32_adc_common_regs {
u32 csr;
u32 ccr;
-   u32 eoc1_msk;
-   u32 eoc2_msk;
-   u32 eoc3_msk;
+   u32 eoc_msk[STM32_ADC_MAX_ADCS];
+   u32 ovr_msk[STM32_ADC_MAX_ADCS];
u32 ier;
u32 eocie_msk;
 };
@@ -282,21 +280,20 @@ static int stm32h7_adc_clk_sel(struct platform_device 
*pdev,
 static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.ccr = STM32F4_ADC_CCR,
-   .eoc1_msk = STM32F4_EOC1 | STM32F4_OVR1,
-   .eoc2_msk = STM32F4_EOC2 | STM32F4_OVR2,
-   .eoc3_msk = STM32F4_EOC3 | STM32F4_OVR3,
+   .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3},
+   .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3},
.ier = STM32F4_ADC_CR1,
-   .eocie_msk = STM32F4_EOCIE | STM32F4_OVRIE,
+   .eocie_msk = STM32F4_EOCIE,
 };
 
 /* STM32H7 common registers definitions */
 static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.ccr = STM32H7_ADC_CCR,
-   .eoc1_msk = STM32H7_EOC_MST | STM32H7_OVR_MST,
-   .eoc2_msk = STM32H7_EOC_SLV | STM32H7_OVR_SLV,
+   .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV},
+   .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV},
.ier = STM32H7_ADC_IER,
-   .eocie_msk = STM32H7_EOCIE | STM32H7_OVRIE,
+   .eocie_msk = STM32H7_EOCIE,
 };
 
 static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {
@@ -318,6 +315,7 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
 {
struct stm32_adc_priv *priv = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
+   int i;
u32 status;
 
chained_irq_enter(chip, desc);
@@ -335,17 +333,12 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
 * before invoking the interrupt handler (e.g. call ISR only for
 * IRQ-enabled ADCs).
 */
-   if (status & priv->cfg->regs->eoc1_msk &&
-   stm32_adc_eoc_enabled(priv, 0))
-   generic_handle_irq(irq_find_mapping(priv->domain, 0));
-
-   if (status & priv->cfg->regs->eoc2_msk &&
-   stm32_adc_eoc_enabled(priv, 1))
-   generic_handle_irq(irq_find_mapping(priv->domain, 1));
-
-   if (status & priv->cfg->regs->eoc3_msk &&
-   stm32_adc_eoc_enabled(priv, 2))
-   generic_handle_irq(irq_find_mapping(priv->domain, 2));
+   for (i = 0; i < priv->cfg->num_irqs; i++) {
+   if ((status & priv->cfg->regs->eoc_msk[i] &&
+stm32_adc_eoc_enabled(priv, i)) ||
+  

[PATCH v2 2/2] dt-bindings: stm32: dfsdm: remove stm32-adfsdm.txt binding

2020-10-20 Thread Olivier Moysan
Device tree audio configuration for STM32 DFSDM is already
covered in the following binding:
Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
Remove stm32-adfsdm.txt obsolete binding.

Signed-off-by: Olivier Moysan 
---
 .../bindings/sound/st,stm32-adfsdm.txt| 63 ---
 1 file changed, 63 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt 
b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt
deleted file mode 100644
index 864f5b00b031..
--- a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-STMicroelectronics Audio Digital Filter Sigma Delta modulators(DFSDM)
-
-The DFSDM allows PDM microphones capture through SPI interface. The Audio
-interface is seems as a sub block of the DFSDM device.
-For details on DFSDM bindings refer to ../iio/adc/st,stm32-dfsdm-adc.txt
-
-Required properties:
-  - compatible: "st,stm32h7-dfsdm-dai".
-
-  - #sound-dai-cells : Must be equal to 0
-
-  - io-channels : phandle to iio dfsdm instance node.
-
-Example of a sound card using audio DFSDM node.
-
-   sound_card {
-   compatible = "audio-graph-card";
-
-   dais = <_port>;
-   };
-
-   dfsdm: dfsdm@40017000 {
-   compatible = "st,stm32h7-dfsdm";
-   reg = <0x40017000 0x400>;
-   clocks = < DFSDM1_CK>;
-   clock-names = "dfsdm";
-   #interrupt-cells = <1>;
-   #address-cells = <1>;
-   #size-cells = <0>;
-
-   dfsdm_adc0: filter@0 {
-   compatible = "st,stm32-dfsdm-dmic";
-   reg = <0>;
-   interrupts = <110>;
-   dmas = < 101 0x400 0x00>;
-   dma-names = "rx";
-   st,adc-channels = <1>;
-   st,adc-channel-names = "dmic0";
-   st,adc-channel-types = "SPI_R";
-   st,adc-channel-clk-src = "CLKOUT";
-   st,filter-order = <5>;
-
-   dfsdm_dai0: dfsdm-dai {
-   compatible = "st,stm32h7-dfsdm-dai";
-   #sound-dai-cells = <0>;
-   io-channels = <_adc0 0>;
-   cpu_port: port {
-   dfsdm_endpoint: endpoint {
-   remote-endpoint = <_endpoint>;
-   };
-   };
-   };
-   };
-
-   dmic0: dmic@0 {
-   compatible = "dmic-codec";
-   #sound-dai-cells = <0>;
-   port {
-   dmic0_endpoint: endpoint {
-   remote-endpoint = <_endpoint>;
-   };
-   };
-   };
-- 
2.17.1



[PATCH v2 1/2] dt-bindings: stm32: dfsdm: update audio properties

2020-10-20 Thread Olivier Moysan
- Add missing compatible property in audio node.
- Remove obsolete "st,stm32-dfsdm-pdm" compatible.
- Remove useless comment in adc io-channels description.

Signed-off-by: Olivier Moysan 
---
 .../devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml| 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml 
b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
index d61bc011e820..6f2398cdc82d 100644
--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml
@@ -199,8 +199,6 @@ patternProperties:
   description:
 From common IIO binding. Used to pipe external sigma delta
 modulator or internal ADC output to DFSDM channel.
-This is not required for "st,stm32-dfsdm-pdm" compatibility as
-PDM microphone is binded in Audio DT node.
 
   required:
 - io-channels
@@ -235,6 +233,10 @@ patternProperties:
   description: child node
 
   properties:
+compatible:
+  enum:
+- st,stm32h7-dfsdm-dai
+
 "#sound-dai-cells":
   const: 0
 
@@ -244,6 +246,7 @@ patternProperties:
 modulator or internal ADC output to DFSDM channel.
 
   required:
+- compatible
 - "#sound-dai-cells"
 - io-channels
 
-- 
2.17.1



[PATCH v2 0/2] dt-bindings: stm32: convert audio dfsdm to json-schema

2020-10-20 Thread Olivier Moysan
Some audio properties documented in st,stm32-adfsdm.txt are already documented
in Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml bindings.
Move remaining properties from st,stm32-adfsdm.txt to st,stm32-dfsdm-adc.yaml,
and remove st,stm32-adfsdm.txt.

Changes in v2:
- Complete st,stm32-dfsdm-adc.yaml rather than converting st,stm32-adfsdm.txt

Olivier Moysan (2):
  dt-bindings: stm32: dfsdm: update audio properties
  dt-bindings: stm32: dfsdm: remove stm32-adfsdm.txt binding

 .../bindings/iio/adc/st,stm32-dfsdm-adc.yaml  |  7 ++-
 .../bindings/sound/st,stm32-adfsdm.txt| 63 ---
 2 files changed, 5 insertions(+), 65 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt

-- 
2.17.1



[PATCH v2] ASoC: cs42l51: manage mclk shutdown delay

2020-10-20 Thread Olivier Moysan
A delay must be introduced before the shutdown down of the mclk,
as stated in CS42L51 datasheet. Otherwise the codec may
produce some noise after the end of DAPM power down sequence.
The delay between DAC and CLOCK_SUPPLY widgets is too short.
Add a delay in mclk shutdown request to manage the shutdown delay
explicitly. From experiments, at least 10ms delay is necessary.
Set delay to 20ms as recommended in Documentation/timers/timers-howto.rst
when using msleep().

Signed-off-by: Olivier Moysan 
---
Recommended Power-Down Sequence:
(see https://statics.cirrus.com/pubs/proDatasheet/CS42L51_F2.pdf)
1.Mute the DACs and ADCs.
2.Disable soft ramp and zero-cross volume transitions
3.Set the PDN bit to 1.
4.Wait at least 100 μs.
The codec will be fully powered down after this 100 μs delay.
Prior to the removal of the master clock(MCLK),
this delay of at least 100 μs must be implemented after step 3
to avoid premature disruption of the codec’s power down sequence.

Changes in v2:
- Manage explicitly DAPM events through a switch case in mclk_event()
---
 sound/soc/codecs/cs42l51.c | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 097c4e8d9950..c61b17dc2af8 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -254,8 +254,28 @@ static const struct snd_soc_dapm_widget 
cs42l51_dapm_widgets[] = {
_adcr_mux_controls),
 };
 
+static int mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+   struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+   struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(comp);
+
+   switch (event) {
+   case SND_SOC_DAPM_PRE_PMU:
+   return clk_prepare_enable(cs42l51->mclk_handle);
+   case SND_SOC_DAPM_POST_PMD:
+   /* Delay mclk shutdown to fulfill power-down sequence 
requirements */
+   msleep(20);
+   clk_disable_unprepare(cs42l51->mclk_handle);
+   break;
+   }
+
+   return 0;
+}
+
 static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = {
-   SND_SOC_DAPM_CLOCK_SUPPLY("MCLK")
+   SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, mclk_event,
+   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route cs42l51_routes[] = {
-- 
2.17.1



[PATCH] ASoC: cs42l51: manage mclk shutdown delay

2020-10-20 Thread Olivier Moysan
A delay must be introduced before the shutdown down of the mclk,
as stated in CS42L51 datasheet. Otherwise the codec may
produce some noise after the end of DAPM power down sequence.
The delay between DAC and CLOCK_SUPPLY widgets is too short.
Add a delay in mclk shutdown request to manage the shutdown delay
explicitly. From experiments, at least 10ms delay is necessary.
Set delay to 20ms as recommended in Documentation/timers/timers-howto.rst
when using msleep().

Signed-off-by: Olivier Moysan 
---
Recommended Power-Down Sequence:
(see https://statics.cirrus.com/pubs/proDatasheet/CS42L51_F2.pdf)
1.Mute the DACs and ADCs.
2.Disable soft ramp and zero-cross volume transitions
3.Set the PDN bit to 1.
4.Wait at least 100 μs.
The codec will be fully powered down after this 100 μs delay.
Prior to the removal of the master clock(MCLK),
this delay of at least 100 μs must be implemented after step 3
to avoid premature disruption of the codec’s power down sequence.
---
 sound/soc/codecs/cs42l51.c | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 097c4e8d9950..d151a1aa313e 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -254,8 +254,25 @@ static const struct snd_soc_dapm_widget 
cs42l51_dapm_widgets[] = {
_adcr_mux_controls),
 };
 
+static int mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+   struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+   struct cs42l51_private *cs42l51 = snd_soc_component_get_drvdata(comp);
+
+   if (SND_SOC_DAPM_EVENT_ON(event))
+   return clk_prepare_enable(cs42l51->mclk_handle);
+
+   /* Delay mclk shutdown to fulfill power-down sequence requirements */
+   msleep(20);
+   clk_disable_unprepare(cs42l51->mclk_handle);
+
+   return 0;
+}
+
 static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = {
-   SND_SOC_DAPM_CLOCK_SUPPLY("MCLK")
+   SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, mclk_event,
+   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route cs42l51_routes[] = {
-- 
2.17.1



[PATCH 1/1] ASoC: dt-bindings: stm32: convert audio dfsdm to json-schema

2020-10-14 Thread Olivier Moysan
Convert the STM32 DFSDM audio bindings to DT schema format
using json-schema.

Signed-off-by: Olivier Moysan 
---
 .../bindings/sound/st,stm32-adfsdm.txt| 63 ---
 .../bindings/sound/st,stm32-adfsdm.yaml   | 42 +
 2 files changed, 42 insertions(+), 63 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt
 create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-adfsdm.yaml

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt 
b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt
deleted file mode 100644
index 864f5b00b031..
--- a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-STMicroelectronics Audio Digital Filter Sigma Delta modulators(DFSDM)
-
-The DFSDM allows PDM microphones capture through SPI interface. The Audio
-interface is seems as a sub block of the DFSDM device.
-For details on DFSDM bindings refer to ../iio/adc/st,stm32-dfsdm-adc.txt
-
-Required properties:
-  - compatible: "st,stm32h7-dfsdm-dai".
-
-  - #sound-dai-cells : Must be equal to 0
-
-  - io-channels : phandle to iio dfsdm instance node.
-
-Example of a sound card using audio DFSDM node.
-
-   sound_card {
-   compatible = "audio-graph-card";
-
-   dais = <_port>;
-   };
-
-   dfsdm: dfsdm@40017000 {
-   compatible = "st,stm32h7-dfsdm";
-   reg = <0x40017000 0x400>;
-   clocks = < DFSDM1_CK>;
-   clock-names = "dfsdm";
-   #interrupt-cells = <1>;
-   #address-cells = <1>;
-   #size-cells = <0>;
-
-   dfsdm_adc0: filter@0 {
-   compatible = "st,stm32-dfsdm-dmic";
-   reg = <0>;
-   interrupts = <110>;
-   dmas = < 101 0x400 0x00>;
-   dma-names = "rx";
-   st,adc-channels = <1>;
-   st,adc-channel-names = "dmic0";
-   st,adc-channel-types = "SPI_R";
-   st,adc-channel-clk-src = "CLKOUT";
-   st,filter-order = <5>;
-
-   dfsdm_dai0: dfsdm-dai {
-   compatible = "st,stm32h7-dfsdm-dai";
-   #sound-dai-cells = <0>;
-   io-channels = <_adc0 0>;
-   cpu_port: port {
-   dfsdm_endpoint: endpoint {
-   remote-endpoint = <_endpoint>;
-   };
-   };
-   };
-   };
-
-   dmic0: dmic@0 {
-   compatible = "dmic-codec";
-   #sound-dai-cells = <0>;
-   port {
-   dmic0_endpoint: endpoint {
-   remote-endpoint = <_endpoint>;
-   };
-   };
-   };
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.yaml 
b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.yaml
new file mode 100644
index ..d953ec524ba2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/st,stm32-adfsdm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics Audio Digital Filter Sigma Delta modulators(DFSDM)
+
+maintainers:
+  - Olivier Moysan 
+
+description:
+  The DFSDM allows PDM microphones capture through the SPI interface.
+  The Audio interface is seen as a sub block of the DFSDM device.
+  For details on DFSDM bindings refer to ../iio/adc/st,stm32-dfsdm-adc.yaml
+
+properties:
+  compatible:
+enum:
+  - st,stm32h7-dfsdm-dai
+
+  "#sound-dai-cells":
+const: 0
+
+  io-channels:
+description: phandle to iio dfsdm instance node
+maxItems: 1
+
+required:
+  - compatible
+  - "#sound-dai-cells"
+  - io-channels
+
+examples:
+  - |
+asoc_pdm0: dfsdm-dai {
+  compatible = "st,stm32h7-dfsdm-dai";
+  #sound-dai-cells = <0>;
+  io-channels = < 0>;
+};
+
+...
-- 
2.17.1



[PATCH v4] ASoC: dt-bindings: stm32: convert sai to json-schema

2020-10-09 Thread Olivier Moysan
Convert the STM32 SAI bindings to DT schema format using json-schema.

Signed-off-by: Olivier Moysan 
---
Changes in v2:
- use pattern for compatible of child nodes
- rework dmas and clocks properties
- add "additionalProperties"

Changes in v3:
- move clocks properties for st,stm32h7-sai compatible, to 'else' clause

Changes in v4:
- fix dtbs_check errors
---
 .../bindings/sound/st,stm32-sai.txt   | 107 --
 .../bindings/sound/st,stm32-sai.yaml  | 200 ++
 2 files changed, 200 insertions(+), 107 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt
 create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.yaml

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt 
b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
deleted file mode 100644
index c42b91e525fa..
--- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
+++ /dev/null
@@ -1,107 +0,0 @@
-STMicroelectronics STM32 Serial Audio Interface (SAI).
-
-The SAI interface (Serial Audio Interface) offers a wide set of audio protocols
-as I2S standards, LSB or MSB-justified, PCM/DSP, TDM, and AC'97.
-The SAI contains two independent audio sub-blocks. Each sub-block has
-its own clock generator and I/O lines controller.
-
-Required properties:
-  - compatible: Should be "st,stm32f4-sai" or "st,stm32h7-sai"
-  - 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 "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
-
-SAI subnodes:
-Two subnodes corresponding to SAI sub-block instances A et B can be defined.
-Subnode can be omitted for unsused sub-block.
-
-SAI subnodes required properties:
-  - compatible: Should be "st,stm32-sai-sub-a" or "st,stm32-sai-sub-b"
-   for SAI sub-block A or B respectively.
-  - reg: Base address and size of SAI sub-block register set.
-  - clocks: Must contain one phandle and clock specifier pair
-   for sai_ck which feeds the internal clock generator.
-   If the SAI shares a master clock, with another SAI set as MCLK
-   clock provider, SAI provider phandle must be specified here.
-  - clock-names: Must contain "sai_ck".
-   Must also contain "MCLK", if SAI shares a master clock,
-   with a SAI set as MCLK clock provider.
-  - dmas: see Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
-  - dma-names: identifier string for each DMA request line
-   "tx": if sai sub-block is configured as playback DAI
-   "rx": if sai sub-block is configured as capture DAI
-  - pinctrl-names: should contain only value "default"
-  - pinctrl-0: see 
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
-
-SAI subnodes Optional properties:
-  - 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.
-  - st,iec60958: support S/PDIF IEC6958 protocol for playback
-   IEC60958 protocol is not available for capture.
-   By default, custom protocol is assumed, meaning that protocol is
-   configured according to protocol defined in related DAI link node,
-   such as i2s, left justified, right justified, dsp and pdm protocols.
-   Note: ac97 protocol is not supported by SAI driver
-   - #clock-cells: should be 0. This property must be present if the SAI device
-   is a master clock provider, according to clocks bindings, described in
-   Documentation/devicetree/bindings/clock/clock-bindings.txt.
-
-The device node should contain one 'port' child node with one child 'endpoint'
-node, according to the bindings defined in Documentation/devicetree/bindings/
-graph.txt.
-
-Example:
-sound_card {
-   compatible = "audio-graph-card";
-   dais = <_port>;
-};
-
-sai1: sai1@40015800 {
-   compatible = "st,stm32h7-sai";
-   #address-cells = <1>;
-   #size-cells = <1>;
-   ranges = <0 0x40015800 0x400>;
-   reg = <0x40015800 0x4>;
-   clocks = < SAI1_CK>, < PLL1_Q>, < PLL2_P>;
-   clock-name

[PATCH 0/2] ASoC: stm32: dfsdm: change rate limits

2020-10-07 Thread Olivier Moysan
Widening of the supported rate range in the STM32 DFSDM driver.
The rates were previously limited to 8kHz, 16kHz and 32kHz.
Allow rate capture in the whole range 8kHz-48kHz as there is no hardware
limitation to support it.
Actual sample resolution is dependent on audio rate and DFSDM configuration. 
Add a trace to allow simple check of sample resolution.

Olivier Moysan (2):
  ASoC: stm32: dfsdm: change rate limits
  ASoC: stm32: dfsdm: add actual resolution trace

 drivers/iio/adc/stm32-dfsdm-adc.c | 4 
 drivers/iio/adc/stm32-dfsdm.h | 2 ++
 sound/soc/stm/stm32_adfsdm.c  | 8 +++-
 3 files changed, 9 insertions(+), 5 deletions(-)

-- 
2.17.1



[PATCH 1/2] ASoC: stm32: dfsdm: change rate limits

2020-10-07 Thread Olivier Moysan
The DFSDM can support a larger rate range than currently
supported in driver.
Increase rate upper limit to 48kHz and allow all rates
in the range 8kHz to 48kHz.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_adfsdm.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index ec27c13af04f..c4031988f981 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -47,9 +47,6 @@ static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
 
-   .rate_min = 8000,
-   .rate_max = 32000,
-
.channels_min = 1,
.channels_max = 1,
 
@@ -143,8 +140,9 @@ static const struct snd_soc_dai_driver stm32_adfsdm_dai = {
.channels_max = 1,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
   SNDRV_PCM_FMTBIT_S32_LE,
-   .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000),
+   .rates = SNDRV_PCM_RATE_CONTINUOUS,
+   .rate_min = 8000,
+   .rate_max = 48000,
},
.ops = _adfsdm_dai_ops,
 };
-- 
2.17.1



[PATCH 2/2] ASoC: stm32: dfsdm: add actual resolution trace

2020-10-07 Thread Olivier Moysan
Add a trace to report actual resolution of audio samples.

Signed-off-by: Olivier Moysan 
---
 drivers/iio/adc/stm32-dfsdm-adc.c | 4 
 drivers/iio/adc/stm32-dfsdm.h | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c 
b/drivers/iio/adc/stm32-dfsdm-adc.c
index 5e10fb4f3704..b7e9ef1a6eec 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -293,6 +293,7 @@ static int stm32_dfsdm_compute_osrs(struct 
stm32_dfsdm_filter *fl,
max >>= flo->rshift;
}
flo->max = (s32)max;
+   flo->bits = bits;
 
pr_debug("%s: fast %d, fosr %d, iosr %d, res 
0x%llx/%d bits, rshift %d, lshift %d\n",
 __func__, fast, flo->fosr, flo->iosr,
@@ -476,6 +477,9 @@ static int stm32_dfsdm_channels_configure(struct iio_dev 
*indio_dev,
if (!flo->res)
return -EINVAL;
 
+   dev_dbg(_dev->dev, "Samples actual resolution: %d bits",
+   min(flo->bits, (u32)DFSDM_DATA_RES - 1));
+
for_each_set_bit(bit, >smask,
 sizeof(adc->smask) * BITS_PER_BYTE) {
chan = indio_dev->channels + bit;
diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h
index 5dbdae4ed881..4afc1f528b78 100644
--- a/drivers/iio/adc/stm32-dfsdm.h
+++ b/drivers/iio/adc/stm32-dfsdm.h
@@ -249,6 +249,7 @@ enum stm32_dfsdm_sinc_order {
  * @rshift: output sample right shift (hardware shift)
  * @lshift: output sample left shift (software shift)
  * @res: output sample resolution
+ * @bits: output sample resolution in bits
  * @max: output sample maximum positive value
  */
 struct stm32_dfsdm_filter_osr {
@@ -257,6 +258,7 @@ struct stm32_dfsdm_filter_osr {
unsigned int rshift;
unsigned int lshift;
u64 res;
+   u32 bits;
s32 max;
 };
 
-- 
2.17.1



[PATCH 1/1] ASoC: cs42l51: add soft dependency declaration

2020-10-02 Thread Olivier Moysan
When configured as module, CS42L51 codec driver uses two modules
snd-soc-cs42l51 and snd-soc-cs42l51-i2c.
Add soft dependency on snd-soc-cs42l51-i2c in snd-soc-cs42l51,
to allow smart module dependency solving.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 097c4e8d9950..1630baad42e2 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -814,4 +814,5 @@ EXPORT_SYMBOL_GPL(cs42l51_of_match);
 
 MODULE_AUTHOR("Arnaud Patard ");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
+MODULE_SOFTDEP("pre: snd-soc-cs42l51-i2c");
 MODULE_LICENSE("GPL");
-- 
2.17.1



[PATCH 0/2] ASoC: stm32: i2s: add master clock provider

2020-09-11 Thread Olivier Moysan
Add master clock generation support in STM32 I2S driver.

Olivier Moysan (2):
  ASoC: dt-bindings: add mclk provider support to stm32 i2s
  ASoC: stm32: i2s: add master clock provider

 .../bindings/sound/st,stm32-i2s.yaml  |   4 +
 sound/soc/stm/stm32_i2s.c | 310 +++---
 2 files changed, 270 insertions(+), 44 deletions(-)

-- 
2.17.1



[PATCH 1/2] ASoC: dt-bindings: add mclk provider support to stm32 i2s

2020-09-11 Thread Olivier Moysan
Add master clock provider support to STM32 I2S.

Signed-off-by: Olivier Moysan 
---
 Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml | 4 
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml 
b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
index f32410890589..6feb5a09c184 100644
--- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml
@@ -54,6 +54,10 @@ properties:
   resets:
 maxItems: 1
 
+  "#clock-cells":
+description: Configure the I2S device as MCLK clock provider.
+const: 0
+
 required:
   - compatible
   - "#sound-dai-cells"
-- 
2.17.1



[PATCH 2/2] ASoC: stm32: i2s: add master clock provider

2020-09-11 Thread Olivier Moysan
Add master clock generation support in STM32 I2S driver.
The master clock provided by I2S can be used to feed a codec.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 310 --
 1 file changed, 266 insertions(+), 44 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 7c4d63c33f15..7d1672cf78cc 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -8,6 +8,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -196,6 +197,9 @@ enum i2s_datlen {
 #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER)
 #define STM32_I2S_IS_SLAVE(x)  ((x)->ms_flg == I2S_MS_SLAVE)
 
+#define STM32_I2S_NAME_LEN 32
+#define STM32_I2S_RATE_11K 11025
+
 /**
  * struct stm32_i2s_data - private data of I2S
  * @regmap_conf: I2S register map configuration pointer
@@ -206,6 +210,7 @@ enum i2s_datlen {
  * @dma_data_rx: dma configuration data for tx channel
  * @substream: PCM substream data pointer
  * @i2sclk: kernel clock feeding the I2S clock generator
+ * @i2smclk: master clock from I2S mclk provider
  * @pclk: peripheral clock driving bus interface
  * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz
  * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz
@@ -215,6 +220,9 @@ enum i2s_datlen {
  * @irq_lock: prevent race condition with IRQ
  * @mclk_rate: master clock frequency (Hz)
  * @fmt: DAI protocol
+ * @divider: prescaler division ratio
+ * @div: prescaler div field
+ * @odd: prescaler odd field
  * @refcount: keep count of opened streams on I2S
  * @ms_flg: master mode flag.
  */
@@ -227,6 +235,7 @@ struct stm32_i2s_data {
struct snd_dmaengine_dai_dma_data dma_data_rx;
struct snd_pcm_substream *substream;
struct clk *i2sclk;
+   struct clk *i2smclk;
struct clk *pclk;
struct clk *x8kclk;
struct clk *x11kclk;
@@ -236,10 +245,210 @@ struct stm32_i2s_data {
spinlock_t irq_lock; /* used to prevent race condition with IRQ */
unsigned int mclk_rate;
unsigned int fmt;
+   unsigned int divider;
+   unsigned int div;
+   bool odd;
int refcount;
int ms_flg;
 };
 
+struct stm32_i2smclk_data {
+   struct clk_hw hw;
+   unsigned long freq;
+   struct stm32_i2s_data *i2s_data;
+};
+
+#define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw)
+
+static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s,
+ unsigned long input_rate,
+ unsigned long output_rate)
+{
+   unsigned int ratio, div, divider = 1;
+   bool odd;
+
+   ratio = DIV_ROUND_CLOSEST(input_rate, output_rate);
+
+   /* Check the parity of the divider */
+   odd = ratio & 0x1;
+
+   /* Compute the div prescaler */
+   div = ratio >> 1;
+
+   /* If div is 0 actual divider is 1 */
+   if (div) {
+   divider = ((2 * div) + odd);
+   dev_dbg(>pdev->dev, "Divider: 2*%d(div)+%d(odd) = %d\n",
+   div, odd, divider);
+   }
+
+   /* Division by three is not allowed by I2S prescaler */
+   if ((div == 1 && odd) || div > I2S_CGFR_I2SDIV_MAX) {
+   dev_err(>pdev->dev, "Wrong divider setting\n");
+   return -EINVAL;
+   }
+
+   if (input_rate % divider)
+   dev_dbg(>pdev->dev,
+   "Rate not accurate. requested (%ld), actual (%ld)\n",
+   output_rate, input_rate / divider);
+
+   i2s->div = div;
+   i2s->odd = odd;
+   i2s->divider = divider;
+
+   return 0;
+}
+
+static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s)
+{
+   u32 cgfr, cgfr_mask;
+
+   cgfr = I2S_CGFR_I2SDIV_SET(i2s->div) | (i2s->odd << I2S_CGFR_ODD_SHIFT);
+   cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD;
+
+   return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+ cgfr_mask, cgfr);
+}
+
+static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s,
+ unsigned int rate)
+{
+   struct platform_device *pdev = i2s->pdev;
+   struct clk *parent_clk;
+   int ret;
+
+   if (!(rate % STM32_I2S_RATE_11K))
+   parent_clk = i2s->x11kclk;
+   else
+   parent_clk = i2s->x8kclk;
+
+   ret = clk_set_parent(i2s->i2sclk, parent_clk);
+   if (ret)
+   dev_err(>dev,
+   "Error %d setting i2sclk parent clock\n", ret);
+
+   return ret;
+}
+
+static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate,
+unsigned long *prate)
+{
+   struct stm32_i2smclk_data *mclk = to_mclk_data(hw);
+ 

[PATCH] ASoC: stm32: sai: add pm_runtime support

2020-09-11 Thread Olivier Moysan
Enable support of pm_runtime on STM32 SAI driver to allow
SAI power state monitoring.
pm_runtime_put_autosuspend() is called from ASoC framework
on pcm device close.
The pmdown_time delay is available in runtime context, and may be set
in SAI driver to take into account shutdown delay on playback.
However, this shutdown delay is already handled in the DAPMs
of the audio codec linked to SAI CPU DAI.
So, the choice is made, not to support this delay on CPU DAI side.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai_sub.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 3fb9513cedb2..3aa1cf262402 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -1559,10 +1560,14 @@ static int stm32_sai_sub_probe(struct platform_device 
*pdev)
 
ret = snd_soc_register_component(>dev, _component,
 >cpu_dai_drv, 1);
-   if (ret)
+   if (ret) {
snd_dmaengine_pcm_unregister(>dev);
+   return ret;
+   }
 
-   return ret;
+   pm_runtime_enable(>dev);
+
+   return 0;
 }
 
 static int stm32_sai_sub_remove(struct platform_device *pdev)
@@ -1572,6 +1577,7 @@ static int stm32_sai_sub_remove(struct platform_device 
*pdev)
clk_unprepare(sai->pdata->pclk);
snd_dmaengine_pcm_unregister(>dev);
snd_soc_unregister_component(>dev);
+   pm_runtime_disable(>dev);
 
return 0;
 }
-- 
2.17.1



[PATCH] ASoC: stm32: sai: fix sysclk management on shutdown

2019-10-18 Thread Olivier Moysan
The commit below, adds a call to sysclk callback on shutdown.
This introduces a regression in stm32 SAI driver, as some clock
services are called twice, leading to unbalanced calls.
Move processing related to mclk from shutdown to sysclk callback.
When requested frequency is 0, assume shutdown and release mclk.

Fixes: 2458adb8f92a ("SoC: simple-card-utils: set 0Hz to sysclk when shutdown")

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai_sub.c | 21 +++--
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index d7501f88aaa6..a4060813bc74 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -505,10 +505,20 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai 
*cpu_dai,
if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 SAI_XCR1_NODIV,
-(unsigned int)~SAI_XCR1_NODIV);
+freq ? 0 : SAI_XCR1_NODIV);
if (ret < 0)
return ret;
 
+   /* Assume shutdown if requested frequency is 0Hz */
+   if (!freq) {
+   /* Release mclk rate only if rate was actually set */
+   if (sai->mclk_rate) {
+   clk_rate_exclusive_put(sai->sai_mclk);
+   sai->mclk_rate = 0;
+   }
+   return 0;
+   }
+
/* If master clock is used, set parent clock now */
ret = stm32_sai_set_parent_clock(sai, freq);
if (ret)
@@ -1093,15 +1103,6 @@ static void stm32_sai_shutdown(struct snd_pcm_substream 
*substream,
 
regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
 
-   regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV,
-  SAI_XCR1_NODIV);
-
-   /* Release mclk rate only if rate was actually set */
-   if (sai->mclk_rate) {
-   clk_rate_exclusive_put(sai->sai_mclk);
-   sai->mclk_rate = 0;
-   }
-
clk_disable_unprepare(sai->sai_ck);
 
spin_lock_irqsave(>irq_lock, flags);
-- 
2.17.1



Re: [PATCH][RFC] iio: core: add a class hierarchy on iio device lock

2019-10-14 Thread Olivier MOYSAN
Hello Jonathan,

Thanks for your comment.

On 10/12/19 10:57 AM, Jonathan Cameron wrote:
> On Fri, 11 Oct 2019 17:13:14 +0200
> Olivier Moysan  wrote:
>
>> The aim of this patch is to correct a recursive locking warning,
>> detected when setting CONFIG_PROVE_LOCKING flag (as shown in message below).
>> This message was initially triggered by the following call sequence
>> in stm32-dfsdm-adc.c driver, when using IIO hardware consumer interface.
>>
>> in stm32_dfsdm_read_raw()
>>  iio_device_claim_direct_mode
>>  mutex_lock(_dev->mlock);  -> lock on 
>> dfsdm device
>>  iio_hw_consumer_enable
>>  iio_update_buffers
>>  mutex_lock(_dev->mlock);  -> lock on hw 
>> consumer device
> Hmm.  I'm not sure I follow the logic.  That lock is
> for one thing and one thing only, preventing access
> to the iio device that are unsafe when it is running
> in a buffered mode.  We shouldn't be in a position where
> we both say don't do this if we are in buffered mode, + enter
> buffered mode whilst doing this, or we need special functions
> for entering buffering mode if in this state.  We are in
> some sense combining internal driver logic with overall
> IIO states.  IIO shouldn't care that the device is using
> the same methods under the hood for buffered and non
> buffered operations.
>
> I can't really recall how this driver works.   Is it actually
> possible to have multiple hw_consumers at the same time?
>
> So do we end up with multiple buffers registered and have
> to demux out to the read_raw + the actual buffered path?
> Given we have a bit of code saying grab one sample, I'm
> going to guess we don't...
>
> If so, the vast majority of the buffer setup code in IIO
> is irrelevant here and we just need to call a few of
> the callbacks from this driver directly... (I think
> though I haven't chased through every corner.
>
> I'd rather avoid introducing this nesting for a corner
> case that makes no 'semantic' sense in IIO as it leaves us
> in two separate states at the same time that the driver
> is trying to make mutually exclusive.  We can't both
> not be in buffered mode, and in buffered mode.
>
> Thanks and good luck with this nasty corner!
>
> Jonathan
>
Here I consider the following use case:
A single conversion is performed. The dfsdm (filter) is chained with a 
front-end, which can be an ADC or a sensor. So we have two IIO devices, 
the dfsdm and its front-end handled through the hw consumer interface.

You are right. There is something wrong here, in buffered/non-buffered 
mode mixing.
iio_hw_consumer_enable() call is used to enable the front-end device. 
But this interface is intended for buffered mode.
So this is not coherent with the expected single conversion mode, 
indeed. Another interface is required to manage the front-end device. I 
have a poor knowledge of iio framework, but it seems to me that there is 
no interface to manage this.

My understanding regarding mlock, is that it is used to protect the 
state of the iio device.
I we want to do a conversion from the chained devices, I think we need 
to activate the first device
and keep it performing conversion, as long as the second device has done 
its conversion.
We need to protect both devices, and we should have to do it in a nested 
way.
So, I guess that anyway, nested mutexes would be required in this case.

Best regards

Olivier

>
>> Here two instances of the same lock class are requested
>> on two different objects.
>> The locking validator needs to be informed of the nesting level
>> of each lock to avoid a false positive.
>>
>> This patch introduces a class hierarchy in iio device lock,
>> assuming that hardware consumer is at a lower level than iio device.
>>
>> [   52.086174]
>> [   52.086223] 
>> [   52.091516] WARNING: possible recursive locking detected
>> [   52.096825] 4.19.49 #162 Not tainted
>> [   52.100384] 
>> [   52.105691] cat/823 is trying to acquire lock:
>> [   52.110132] 37acb703 (>mlock){+.+.}, at: iio_update_buffers+0x3c/0xd0
>> [   52.116995]
>> [   52.116995] but task is already holding lock:
>> [   52.122821] 368bb908 (>mlock){+.+.}, at: 
>> iio_device_claim_direct_mode+0x18/0x34
>> [   52.130560]
>> [   52.130560] other info that might help us debug this:
>> [   52.137083]  Possible unsafe locking scenario:
>> [   52.137083]
>> [   52.142995]CPU0
>> [   52.145430]
>> [   52.147864]   lock(>mlock);
>> [   52.151082]   lock(>mlock);
>> [

[PATCH][RFC] iio: core: add a class hierarchy on iio device lock

2019-10-11 Thread Olivier Moysan
The aim of this patch is to correct a recursive locking warning,
detected when setting CONFIG_PROVE_LOCKING flag (as shown in message below).
This message was initially triggered by the following call sequence
in stm32-dfsdm-adc.c driver, when using IIO hardware consumer interface.

in stm32_dfsdm_read_raw()
iio_device_claim_direct_mode
mutex_lock(_dev->mlock);  -> lock on 
dfsdm device
iio_hw_consumer_enable
iio_update_buffers
mutex_lock(_dev->mlock);  -> lock on hw 
consumer device

Here two instances of the same lock class are requested
on two different objects.
The locking validator needs to be informed of the nesting level
of each lock to avoid a false positive.

This patch introduces a class hierarchy in iio device lock,
assuming that hardware consumer is at a lower level than iio device.

[   52.086174]
[   52.086223] 
[   52.091516] WARNING: possible recursive locking detected
[   52.096825] 4.19.49 #162 Not tainted
[   52.100384] 
[   52.105691] cat/823 is trying to acquire lock:
[   52.110132] 37acb703 (>mlock){+.+.}, at: iio_update_buffers+0x3c/0xd0
[   52.116995]
[   52.116995] but task is already holding lock:
[   52.122821] 368bb908 (>mlock){+.+.}, at: 
iio_device_claim_direct_mode+0x18/0x34
[   52.130560]
[   52.130560] other info that might help us debug this:
[   52.137083]  Possible unsafe locking scenario:
[   52.137083]
[   52.142995]CPU0
[   52.145430]
[   52.147864]   lock(>mlock);
[   52.151082]   lock(>mlock);
[   52.154301]
[   52.154301]  * DEADLOCK *
[   52.154301]
[   52.160215]  May be due to missing lock nesting notation
[   52.160215]
[   52.167000] 5 locks held by cat/823:
[   52.170563]  #0: 96d6554b (>lock){+.+.}, at: seq_read+0x34/0x51c
[   52.176824]  #1: 3cf6739a (>mutex){+.+.}, at: kernfs_seq_start+0x1c/0x8c
[   52.183866]  #2: a6090e0a (kn->count#29){.+.+}, at: 
kernfs_seq_start+0x24/0x8c
[   52.191083]  #3: 368bb908 (>mlock){+.+.}, at: 
iio_device_claim_direct_mode+0x18/0x34
[   52.199257]  #4: 77e2bcfe (>info_exist_lock){+.+.}, at: 
iio_update_buffers+0x30/0xd0
[   52.207431]
[   52.207431] stack backtrace:
[   52.211787] CPU: 0 PID: 823 Comm: cat Not tainted 4.19.49 #162
[   52.217606] Hardware name: STM32 (Device Tree Support)
[   52.222756] [] (unwind_backtrace) from [] 
(show_stack+0x10/0x14)
[   52.230487] [] (show_stack) from [] 
(dump_stack+0xc4/0xf0)
[   52.237703] [] (dump_stack) from [] 
(__lock_acquire+0x874/0x1344)
[   52.245525] [] (__lock_acquire) from [] 
(lock_acquire+0xd8/0x268)
[   52.253353] [] (lock_acquire) from [] 
(__mutex_lock+0x70/0xab0)
[   52.261005] [] (__mutex_lock) from [] 
(mutex_lock_nested+0x1c/0x24)
[   52.269001] [] (mutex_lock_nested) from [] 
(iio_update_buffers+0x3c/0xd0)
[   52.277523] [] (iio_update_buffers) from [] 
(iio_hw_consumer_enable+0x34/0x70)
[   52.286476] [] (iio_hw_consumer_enable) from [] 
(stm32_dfsdm_read_raw+0xf4/0x3fc)
[   52.295695] [] (stm32_dfsdm_read_raw) from [] 
(iio_read_channel_info+0xa8/0xb0)
[   52.304738] [] (iio_read_channel_info) from [] 
(dev_attr_show+0x1c/0x48)
[   52.313170] [] (dev_attr_show) from [] 
(sysfs_kf_seq_show+0x84/0xec)
[   52.321256] [] (sysfs_kf_seq_show) from [] 
(seq_read+0x154/0x51c)
[   52.329082] [] (seq_read) from [] (__vfs_read+0x2c/0x15c)
[   52.336209] [] (__vfs_read) from [] (vfs_read+0x90/0x15c)
[   52.343339] [] (vfs_read) from [] (ksys_read+0x5c/0xdc)
[   52.350296] [] (ksys_read) from [] 
(ret_fast_syscall+0x0/0x28)
[   52.357852] Exception stack(0xe5761fa8 to 0xe5761ff0)
[   52.362904] 1fa0:   006c 7ff0 0003 b6e06000 
0002 
[   52.371077] 1fc0: 006c 7ff0 0002 0003 0003  
0002 
[   52.379245] 1fe0: 0003 beb6e790 b6eb17b7 b6e3e6c6

Signed-off-by: Olivier Moysan 
---
 drivers/iio/buffer/industrialio-hw-consumer.c | 9 -
 drivers/iio/industrialio-buffer.c | 2 +-
 drivers/iio/industrialio-core.c   | 3 ++-
 include/linux/iio/iio.h   | 6 ++
 4 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c 
b/drivers/iio/buffer/industrialio-hw-consumer.c
index 95165697d8ae..652ce31b4b5f 100644
--- a/drivers/iio/buffer/industrialio-hw-consumer.c
+++ b/drivers/iio/buffer/industrialio-hw-consumer.c
@@ -101,6 +101,7 @@ struct iio_hw_consumer *iio_hw_consumer_alloc(struct device 
*dev)
 
chan = >channels[0];
while (chan->indio_dev) {
+   chan->indio_dev->mutex_class = IIO_MUTEX_HWC;
buf = iio_hw_consumer_get_buffer(hwc, chan->indio_dev);
if (!buf) {
ret = -ENOMEM;
@@ -129,8 +130,14 @@ EXPORT_SYMBOL_GPL(iio_hw_consumer_alloc);
 void iio_hw_consum

[PATCH] ASoC: stm32: spdifrx: retry synchronization in sync state

2019-10-11 Thread Olivier Moysan
When STM32 SPDIFRX is in sync state, allow multiple
synchro attempts, instead of exiting on first unsuccessful
trial. This is useful when spdif signal is not immediately
available on input. This also allows Pulseaudio to check
iec capture device availability when no signal is present.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_spdifrx.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index cd4b235fce57..3fd28ee01675 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -351,6 +351,8 @@ static int stm32_spdifrx_start_sync(struct 
stm32_spdifrx_data *spdifrx)
 SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO;
cr_mask = cr;
 
+   cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63);
+   cr_mask |= SPDIFRX_CR_NBTR_MASK;
cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC);
cr_mask |= SPDIFRX_CR_SPDIFEN_MASK;
ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
@@ -666,7 +668,7 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
struct snd_pcm_substream *substream = spdifrx->substream;
struct platform_device *pdev = spdifrx->pdev;
unsigned int cr, mask, sr, imr;
-   unsigned int flags;
+   unsigned int flags, sync_state;
int err = 0, err_xrun = 0;
 
regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, );
@@ -726,11 +728,23 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
}
 
if (err) {
-   /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */
+   regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, );
+   sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) &&
+SPDIFRX_SPDIFEN_SYNC;
+
+   /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */
cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE);
regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
   SPDIFRX_CR_SPDIFEN_MASK, cr);
 
+   /* If SPDIFRX was in STATE_SYNC, retry synchro */
+   if (sync_state) {
+   cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC);
+   regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR,
+  SPDIFRX_CR_SPDIFEN_MASK, cr);
+   return IRQ_HANDLED;
+   }
+
if (substream)
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
 
-- 
2.17.1



[PATCH] ARM: dts: stm32: add hdmi audio support to stm32mp157a-dk1 board

2019-10-10 Thread Olivier Moysan
Add HDMI audio support through Sil9022 HDMI transceiver
on stm32mp157a-dk1 board.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157a-dk1.dts | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts 
b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index 5ad4cef9e971..7a20640c00a9 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -92,7 +92,7 @@
"Playback" , "MCLK",
"Capture" , "MCLK",
"MICL" , "Mic Bias";
-   dais = <_port _port>;
+   dais = <_port _port _port>;
status = "okay";
};
 };
@@ -173,6 +173,7 @@
reset-gpios = < 10 GPIO_ACTIVE_LOW>;
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <>;
+   #sound-dai-cells = <0>;
status = "okay";
 
ports {
@@ -185,6 +186,13 @@
remote-endpoint = <_ep0_out>;
};
};
+
+   port@3 {
+   reg = <3>;
+   sii9022_tx_endpoint: endpoint {
+   remote-endpoint = <_endpoint>;
+   };
+   };
};
};
 
@@ -370,6 +378,23 @@
};
 };
 
+ {
+   clocks = < SPI2>, < SPI2_K>, < PLL3_Q>, < PLL3_R>;
+   clock-names = "pclk", "i2sclk", "x8k", "x11k";
+   pinctrl-names = "default", "sleep";
+   pinctrl-0 = <_pins_a>;
+   pinctrl-1 = <_pins_sleep_a>;
+   status = "okay";
+
+   i2s2_port: port {
+   i2s2_endpoint: endpoint {
+   remote-endpoint = <_tx_endpoint>;
+   format = "i2s";
+   mclk-fs = <256>;
+   };
+   };
+};
+
  {
status = "okay";
 };
-- 
2.17.1



[PATCH 0/4] ARM: multi_v7_defconfig: add audio support for stm32mp157a-dk1

2019-09-02 Thread Olivier Moysan
This patchset adds audio support for stm32mp157a-dk1 board.

Olivier Moysan (4):
  ARM: multi_v7_defconfig: enable stm32 sai support
  ARM: multi_v7_defconfig: enable stm32 i2s support
  ARM: multi_v7_defconfig: enable cs42l51 codec support
  ARM: multi_v7_defconfig: enable audio graph card support

 arch/arm/configs/multi_v7_defconfig | 4 
 1 file changed, 4 insertions(+)

-- 
2.7.4



[PATCH 2/4] ARM: multi_v7_defconfig: enable stm32 i2s support

2019-09-02 Thread Olivier Moysan
Enable support for I2S on STM32MP1.

Signed-off-by: Olivier Moysan 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 929d13842171..02265e195e50 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -700,6 +700,7 @@ CONFIG_SND_SOC_SH4_FSI=m
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_STI=m
 CONFIG_SND_SOC_STM32_SAI=m
+CONFIG_SND_SOC_STM32_I2S=m
 CONFIG_SND_SUN4I_CODEC=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA20_I2S=m
-- 
2.7.4



[PATCH 3/4] ARM: multi_v7_defconfig: enable cs42l51 codec support

2019-09-02 Thread Olivier Moysan
Enable Cirrus CS42L51 audio codec for stm32mp157a-dk1 board.

Signed-off-by: Olivier Moysan 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 02265e195e50..03a4d93df8c4 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -714,6 +714,7 @@ CONFIG_SND_SOC_TEGRA_ALC5632=m
 CONFIG_SND_SOC_TEGRA_MAX98090=m
 CONFIG_SND_SOC_AK4642=m
 CONFIG_SND_SOC_CPCAP=m
+CONFIG_SND_SOC_CS42L51_I2C=m
 CONFIG_SND_SOC_SGTL5000=m
 CONFIG_SND_SOC_SPDIF=m
 CONFIG_SND_SOC_STI_SAS=m
-- 
2.7.4



[PATCH 1/4] ARM: multi_v7_defconfig: enable stm32 sai support

2019-09-02 Thread Olivier Moysan
Enable support for SAI on STM32MP1.

Signed-off-by: Olivier Moysan 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index c5d37dfafe98..929d13842171 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -699,6 +699,7 @@ CONFIG_SND_SOC_ODROID=m
 CONFIG_SND_SOC_SH4_FSI=m
 CONFIG_SND_SOC_RCAR=m
 CONFIG_SND_SOC_STI=m
+CONFIG_SND_SOC_STM32_SAI=m
 CONFIG_SND_SUN4I_CODEC=m
 CONFIG_SND_SOC_TEGRA=m
 CONFIG_SND_SOC_TEGRA20_I2S=m
-- 
2.7.4



[PATCH 4/4] ARM: multi_v7_defconfig: enable audio graph card support

2019-09-02 Thread Olivier Moysan
Enable audio graph card support for stm32mp157a-dk1 board.

Signed-off-by: Olivier Moysan 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 03a4d93df8c4..c7104a1c1687 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -719,6 +719,7 @@ CONFIG_SND_SOC_SGTL5000=m
 CONFIG_SND_SOC_SPDIF=m
 CONFIG_SND_SOC_STI_SAS=m
 CONFIG_SND_SOC_WM8978=m
+CONFIG_SND_AUDIO_GRAPH_CARD=m
 CONFIG_USB=y
 CONFIG_USB_OTG=y
 CONFIG_USB_XHCI_HCD=y
-- 
2.7.4



Re: [PATCH] ARM: dts: stm32: add DFSDM pins to stm32mp157c

2019-08-02 Thread Olivier MOYSAN
Hi ALex,

On 8/2/19 10:09 AM, Alexandre Torgue wrote:
> Hi Olivier
> 
> On 8/1/19 9:46 AM, Olivier Moysan wrote:
>> Add DFSDM pins to stm32mp157c.
>>
>> Signed-off-by: Olivier Moysan 
>> ---
>>arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 39 
>> +++
>>1 file changed, 39 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi 
>> b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
>> index 9eaec9bf8cb8..f96a928cbc49 100644
>> --- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
>> +++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
>> @@ -230,6 +230,45 @@
>>  };
>>  };
>>
> 
> I use to only take pinconfig which are used in board. So please resend
> with the "board patch".
> 

The DFSDM is one of the interface used in the STM32MP15 soundcard.
This soundcard also uses the Wolfson wm8994 audio codec.
The wm8994 codec driver requires adaptations, and the upstream of
these changes is not planned today.
So, the related board patches cannot be sent.

BRs
Olivier

> regards
> Alex
> 
> 
>> +dfsdm_clkout_pins_a: dfsdm-clkout-pins-0 {
>> +pins {
>> +pinmux = ; 
>> /* DFSDM_CKOUT */
>> +bias-disable;
>> +drive-push-pull;
>> +slew-rate = <0>;
>> +};
>> +};
>> +
>> +dfsdm_clkout_sleep_pins_a: dfsdm-clkout-sleep-pins-0 {
>> +pins {
>> +pinmux = > ANALOG)>; /* DFSDM_CKOUT */
>> +};
>> +};
>> +
>> +dfsdm_data1_pins_a: dfsdm-data1-pins-0 {
>> +pins {
>> +pinmux = ; 
>> /* DFSDM_DATA1 */
>> +};
>> +};
>> +
>> +dfsdm_data1_sleep_pins_a: dfsdm-data1-sleep-pins-0 {
>> +pins {
>> +pinmux = > ANALOG)>; /* DFSDM_DATA1 */
>> +};
>> +};
>> +
>> +dfsdm_data3_pins_a: dfsdm-data3-pins-0 {
>> +pins {
>> +pinmux = ; 
>> /* DFSDM_DATA3 */
>> +};
>> +};
>> +
>> +dfsdm_data3_sleep_pins_a: dfsdm-data3-sleep-pins-0 {
>> +pins {
>> +pinmux = > ANALOG)>; /* DFSDM_DATA3 */
>> +};
>> +};
>> +
>>  ethernet0_rgmii_pins_a: rgmii-0 {
>>  pins1 {
>>  pinmux = , 
>> /* ETH_RGMII_CLK125 */
>>

[PATCH] ARM: dts: stm32: add DFSDM pins to stm32mp157c

2019-08-01 Thread Olivier Moysan
Add DFSDM pins to stm32mp157c.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 9eaec9bf8cb8..f96a928cbc49 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -230,6 +230,45 @@
};
};
 
+   dfsdm_clkout_pins_a: dfsdm-clkout-pins-0 {
+   pins {
+   pinmux = ; 
/* DFSDM_CKOUT */
+   bias-disable;
+   drive-push-pull;
+   slew-rate = <0>;
+   };
+   };
+
+   dfsdm_clkout_sleep_pins_a: dfsdm-clkout-sleep-pins-0 {
+   pins {
+   pinmux = ; /* DFSDM_CKOUT */
+   };
+   };
+
+   dfsdm_data1_pins_a: dfsdm-data1-pins-0 {
+   pins {
+   pinmux = ; 
/* DFSDM_DATA1 */
+   };
+   };
+
+   dfsdm_data1_sleep_pins_a: dfsdm-data1-sleep-pins-0 {
+   pins {
+   pinmux = ; /* DFSDM_DATA1 */
+   };
+   };
+
+   dfsdm_data3_pins_a: dfsdm-data3-pins-0 {
+   pins {
+   pinmux = ; 
/* DFSDM_DATA3 */
+   };
+   };
+
+   dfsdm_data3_sleep_pins_a: dfsdm-data3-sleep-pins-0 {
+   pins {
+   pinmux = ; /* DFSDM_DATA3 */
+   };
+   };
+
ethernet0_rgmii_pins_a: rgmii-0 {
pins1 {
pinmux = , 
/* ETH_RGMII_CLK125 */
-- 
2.7.4



Re: [PATCH] ARM: dts: stm32: add audio codec support on stm32mp157a-dk1 board

2019-07-25 Thread Olivier MOYSAN


On 7/24/19 6:40 PM, Alexandre Torgue wrote:
> Hi Olivier
> 
> On 7/5/19 1:53 PM, Olivier Moysan wrote:
>> Add support of Cirrus cs42l51 audio codec on stm32mp157a-dk1 board.
>> Configuration overview:
>> - SAI2A is the CPU interface used for the codec audio playback
>> - SAI2B is the CPU interface used for the codec audio record
>> - SAI2A is configured as a clock provider for the audio codec
>> - SAI2A are configured as slave of the audio codec
>> - SAI2A share the same interface of the audio codec
>>
>> Note:
>> In master mode, cs42l51 audio codec provides a bitclock
>> at 64 x FS, regardless of data width. This means that
>> slot width is always 32 bits.
>> Set slot width to 32 bits and slot number to 2
>> in SAI2A endpoint nodes, to match this constraint.
>> dai-tdm-slot-num and dai-tdm-slot-width properties are used here,
>> assuming that i2s is a special case of tdm, where slot number is 2.
>>
>> Signed-off-by: Olivier Moysan 
>> ---
>>arch/arm/boot/dts/stm32mp157a-dk1.dts | 89 
>> +++
>>1 file changed, 89 insertions(+)
>>
> 
> ...
> 
>>
>> + {
>> +clocks = < SAI2>, < PLL3_Q>, < PLL3_R>;
>> +clock-names = "pclk", "x8k", "x11k";
>> +pinctrl-names = "default", "sleep";
>> +pinctrl-0 = <_pins_a>, <_pins_b>;
>> +pinctrl-1 = <_sleep_pins_a>, <_sleep_pins_b>;
>> +status = "okay";
>> +
>> +sai2a: audio-controller@4400b004 {
>> +#clock-cells = <0>;
>> +dma-names = "tx";
>> +clocks = < SAI2_K>;
>> +clock-names = "sai_ck";
>> +status = "okay";
>> +
>> +sai2a_port: port {
>> +sai2a_endpoint: endpoint {
>> +remote-endpoint = <_tx_endpoint>;
>> +format = "i2s";
>> +mclk-fs = <256>;
>> +dai-tdm-slot-num = <2>;
>> +dai-tdm-slot-width = <32>;
>> +};
>> +};
>> +};
>> +
> You could use label to overload sai2a and sai2b. no ?
I propose to keep it unchanged for better readability
> 
>> +sai2b: audio-controller@4400b024 {
>> +dma-names = "rx";
>> +st,sync = < 2>;
>> +clocks = < SAI2_K>, <>;
>> +clock-names = "sai_ck", "MCLK";
>> +status = "okay";
>> +
>> +sai2b_port: port {
>> +sai2b_endpoint: endpoint {
>> +remote-endpoint = <_rx_endpoint>;
>> +format = "i2s";
>> +mclk-fs = <256>;
>> +dai-tdm-slot-num = <2>;
>> +dai-tdm-slot-width = <32>;
>> +};
>> +};
>> +};
>> +};
>> +
>> {
>>  pinctrl-names = "default", "opendrain", "sleep";
>>  pinctrl-0 = <_b4_pins_a>;
>>

[PATCH] ARM: dts: stm32: add audio codec support on stm32mp157a-dk1 board

2019-07-05 Thread Olivier Moysan
Add support of Cirrus cs42l51 audio codec on stm32mp157a-dk1 board.
Configuration overview:
- SAI2A is the CPU interface used for the codec audio playback
- SAI2B is the CPU interface used for the codec audio record
- SAI2A is configured as a clock provider for the audio codec
- SAI2A are configured as slave of the audio codec
- SAI2A share the same interface of the audio codec

Note:
In master mode, cs42l51 audio codec provides a bitclock
at 64 x FS, regardless of data width. This means that
slot width is always 32 bits.
Set slot width to 32 bits and slot number to 2
in SAI2A endpoint nodes, to match this constraint.
dai-tdm-slot-num and dai-tdm-slot-width properties are used here,
assuming that i2s is a special case of tdm, where slot number is 2.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157a-dk1.dts | 89 +++
 1 file changed, 89 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts 
b/arch/arm/boot/dts/stm32mp157a-dk1.dts
index f3f0e37aad4d..0f5b3c77153d 100644
--- a/arch/arm/boot/dts/stm32mp157a-dk1.dts
+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts
@@ -48,6 +48,17 @@
default-state = "off";
};
};
+
+   sound {
+   compatible = "audio-graph-card";
+   label = "STM32MP1-DK";
+   routing =
+   "Playback" , "MCLK",
+   "Capture" , "MCLK",
+   "MICL" , "Mic Bias";
+   dais = <_port _port>;
+   status = "okay";
+   };
 };
 
  {
@@ -116,6 +127,39 @@
};
};
};
+
+   cs42l51: cs42l51@4a {
+   compatible = "cirrus,cs42l51";
+   reg = <0x4a>;
+   #sound-dai-cells = <0>;
+   VL-supply = <>;
+   VD-supply = <_audio>;
+   VA-supply = <_audio>;
+   VAHP-supply = <_audio>;
+   reset-gpios = < 9 GPIO_ACTIVE_LOW>;
+   clocks = <>;
+   clock-names = "MCLK";
+   status = "okay";
+
+   cs42l51_port: port {
+   #address-cells = <1>;
+   #size-cells = <0>;
+
+   cs42l51_tx_endpoint: endpoint@0 {
+   reg = <0>;
+   remote-endpoint = <_endpoint>;
+   frame-master;
+   bitclock-master;
+   };
+
+   cs42l51_rx_endpoint: endpoint@1 {
+   reg = <1>;
+   remote-endpoint = <_endpoint>;
+   frame-master;
+   bitclock-master;
+   };
+   };
+   };
 };
 
  {
@@ -297,6 +341,51 @@
status = "okay";
 };
 
+ {
+   clocks = < SAI2>, < PLL3_Q>, < PLL3_R>;
+   clock-names = "pclk", "x8k", "x11k";
+   pinctrl-names = "default", "sleep";
+   pinctrl-0 = <_pins_a>, <_pins_b>;
+   pinctrl-1 = <_sleep_pins_a>, <_sleep_pins_b>;
+   status = "okay";
+
+   sai2a: audio-controller@4400b004 {
+   #clock-cells = <0>;
+   dma-names = "tx";
+   clocks = < SAI2_K>;
+   clock-names = "sai_ck";
+   status = "okay";
+
+   sai2a_port: port {
+   sai2a_endpoint: endpoint {
+   remote-endpoint = <_tx_endpoint>;
+   format = "i2s";
+   mclk-fs = <256>;
+   dai-tdm-slot-num = <2>;
+   dai-tdm-slot-width = <32>;
+   };
+   };
+   };
+
+   sai2b: audio-controller@4400b024 {
+   dma-names = "rx";
+   st,sync = < 2>;
+   clocks = < SAI2_K>, <>;
+   clock-names = "sai_ck", "MCLK";
+   status = "okay";
+
+   sai2b_port: port {
+   sai2b_endpoint: endpoint {
+   remote-endpoint = <_rx_endpoint>;
+   format = "i2s";
+   mclk-fs = <256>;
+   dai-tdm-slot-num = <2>;
+   dai-tdm-slot-width = <32>;
+   };
+   };
+   };
+};
+
  {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <_b4_pins_a>;
-- 
2.7.4



[PATCH 4/5] iio: adc: stm32-dfsdm: add fast mode support

2019-06-19 Thread Olivier Moysan
The use of fast mode allows to get a larger set of solution
for filter parameters. This can be useful to reach a better
output sample resolution, when fast mode can be used.

Fast mode is selected at startup if it is relevant.
The startup is performed in postenable callback context,
where there are too tight time constraints for filter parameters
computation. For this reason both fast and non fast filter parameters
are pre-computed previously.

Signed-off-by: Olivier Moysan 
---
 drivers/iio/adc/stm32-dfsdm-adc.c | 65 ++-
 drivers/iio/adc/stm32-dfsdm.h |  4 +--
 2 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c 
b/drivers/iio/adc/stm32-dfsdm-adc.c
index 5b19a88412a6..d855a605eab6 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -196,7 +196,7 @@ static int stm32_dfsdm_compute_osrs(struct 
stm32_dfsdm_filter *fl,
int bits, shift;
unsigned int m = 1; /* multiplication factor */
unsigned int p = fl->ford;  /* filter order (ford) */
-   struct stm32_dfsdm_filter_osr *flo = >flo;
+   struct stm32_dfsdm_filter_osr *flo = >flo[fast];
 
pr_debug("%s: Requested oversampling: %d\n",  __func__, oversamp);
/*
@@ -217,7 +217,6 @@ static int stm32_dfsdm_compute_osrs(struct 
stm32_dfsdm_filter *fl,
 * Look for filter and integrator oversampling ratios which allows
 * to maximize data output resolution.
 */
-   flo->res = 0;
for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) {
for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) {
if (fast)
@@ -309,6 +308,28 @@ static int stm32_dfsdm_compute_osrs(struct 
stm32_dfsdm_filter *fl,
return 0;
 }
 
+static int stm32_dfsdm_compute_all_osrs(struct iio_dev *indio_dev,
+   unsigned int oversamp)
+{
+   struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+   struct stm32_dfsdm_filter *fl = >dfsdm->fl_list[adc->fl_id];
+   int ret0, ret1;
+
+   memset(>flo[0], 0, sizeof(fl->flo[0]));
+   memset(>flo[1], 0, sizeof(fl->flo[1]));
+
+   ret0 = stm32_dfsdm_compute_osrs(fl, 0, oversamp);
+   ret1 = stm32_dfsdm_compute_osrs(fl, 1, oversamp);
+   if (ret0 < 0 && ret1 < 0) {
+   dev_err(_dev->dev,
+   "Filter parameters not found: errors %d/%d\n",
+   ret0, ret1);
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 static int stm32_dfsdm_start_channel(struct stm32_dfsdm_adc *adc)
 {
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
@@ -433,11 +454,25 @@ static int stm32_dfsdm_channels_configure(struct 
stm32_dfsdm_adc *adc,
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
struct regmap *regmap = adc->dfsdm->regmap;
struct stm32_dfsdm_filter *fl = >dfsdm->fl_list[fl_id];
-   struct stm32_dfsdm_filter_osr *flo = >flo;
+   struct stm32_dfsdm_filter_osr *flo = >flo[0];
const struct iio_chan_spec *chan;
unsigned int bit;
int ret;
 
+   fl->fast = 0;
+
+   /*
+* In continuous mode, use fast mode configuration,
+* if it provides a better resolution.
+*/
+   if (adc->nconv == 1 && !trig &&
+   (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE)) {
+   if (fl->flo[1].res >= fl->flo[0].res) {
+   fl->fast = 1;
+   flo = >flo[1];
+   }
+   }
+
if (!flo->res)
return -EINVAL;
 
@@ -463,7 +498,7 @@ static int stm32_dfsdm_filter_configure(struct 
stm32_dfsdm_adc *adc,
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
struct regmap *regmap = adc->dfsdm->regmap;
struct stm32_dfsdm_filter *fl = >dfsdm->fl_list[fl_id];
-   struct stm32_dfsdm_filter_osr *flo = >flo;
+   struct stm32_dfsdm_filter_osr *flo = >flo[fl->fast];
u32 cr1;
const struct iio_chan_spec *chan;
unsigned int bit, jchg = 0;
@@ -490,6 +525,12 @@ static int stm32_dfsdm_filter_configure(struct 
stm32_dfsdm_adc *adc,
if (ret)
return ret;
 
+   ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id),
+DFSDM_CR1_FAST_MASK,
+DFSDM_CR1_FAST(fl->fast));
+   if (ret)
+   return ret;
+
/*
 * DFSDM modes configuration W.R.T audio/iio type modes
 * 
@@ -636,7 +677,6 @@ static int dfsdm_adc_set_samp_freq(struct iio_dev 
*indio_dev,
   unsigned int spi_freq)
 {
struct stm32_dfsdm_adc *adc = iio_pri

[PATCH 5/5] iio: adc: stm32-dfsdm: add comment for 16 bits record

2019-06-19 Thread Olivier Moysan
Add a comment on DMA configuration for 16 bits record.

Signed-off-by: Olivier Moysan 
---
 drivers/iio/adc/stm32-dfsdm-adc.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c 
b/drivers/iio/adc/stm32-dfsdm-adc.c
index d855a605eab6..ee1e0569d0e1 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -918,6 +918,11 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
 static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
 {
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+   /*
+* The DFSDM supports half-word transfers. However, for 16 bits record,
+* 4 bytes buswidth is kept, to avoid losing samples LSBs when left
+* shift is required.
+*/
struct dma_slave_config config = {
.src_addr = (dma_addr_t)adc->dfsdm->phys_base,
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
-- 
2.7.4



[PATCH 2/5] iio: adc: stm32-dfsdm: fix data type

2019-06-19 Thread Olivier Moysan
Fix the data type as DFSDM raw output is complements 2,
24bits left aligned in a 32-bit register.
This change does not affect AUDIO path
- Set data as signed for IIO (as for AUDIO)
- Set 8 bit right shift for IIO.
The 8 LSBs bits of data contains channel info and are masked.

Fixes: e2e6771c6462 ("IIO: ADC: add STM32 DFSDM sigma delta ADC support")

Signed-off-by: Olivier Moysan 
---
 drivers/iio/adc/stm32-dfsdm-adc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c 
b/drivers/iio/adc/stm32-dfsdm-adc.c
index cb596f104919..6b90a40882f2 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -1365,11 +1365,11 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev 
*indio_dev,
BIT(IIO_CHAN_INFO_SAMP_FREQ);
 
if (adc->dev_data->type == DFSDM_AUDIO) {
-   ch->scan_type.sign = 's';
ch->ext_info = dfsdm_adc_audio_ext_info;
} else {
-   ch->scan_type.sign = 'u';
+   ch->scan_type.shift = 8;
}
+   ch->scan_type.sign = 's';
ch->scan_type.realbits = 24;
ch->scan_type.storagebits = 32;
 
-- 
2.7.4



[PATCH 3/5] iio: adc: stm32-dfsdm: manage data resolution in trigger mode

2019-06-19 Thread Olivier Moysan
Add output sample resolution management in scan mode.
Add stm32_dfsdm_process_data() function to share sample
processing between continuous and trigger modes.

Signed-off-by: Olivier Moysan 
---
 drivers/iio/adc/stm32-dfsdm-adc.c | 41 ++-
 1 file changed, 28 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c 
b/drivers/iio/adc/stm32-dfsdm-adc.c
index 6b90a40882f2..5b19a88412a6 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -779,6 +779,30 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct 
stm32_dfsdm_adc *adc)
return 0;
 }
 
+static inline void stm32_dfsdm_process_data(struct stm32_dfsdm_adc *adc,
+   s32 *buffer)
+{
+   struct stm32_dfsdm_filter *fl = >dfsdm->fl_list[adc->fl_id];
+   struct stm32_dfsdm_filter_osr *flo = >flo;
+   unsigned int i = adc->nconv;
+   s32 *ptr = buffer;
+
+   while (i--) {
+   /* Mask 8 LSB that contains the channel ID */
+   *ptr &= 0xFF00;
+   /* Convert 2^(n-1) sample to 2^(n-1)-1 to avoid wrap-around */
+   if (*ptr > flo->max)
+   *ptr -= 1;
+   /*
+* Samples from filter are retrieved with 23 bits resolution
+* or less. Shift left to align MSB on 24 bits.
+*/
+   *ptr <<= flo->lshift;
+
+   ptr++;
+   }
+}
+
 static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
 {
struct iio_poll_func *pf = p;
@@ -787,7 +811,9 @@ static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, 
void *p)
int available = stm32_dfsdm_adc_dma_residue(adc);
 
while (available >= indio_dev->scan_bytes) {
-   u32 *buffer = (u32 *)>rx_buf[adc->bufi];
+   s32 *buffer = (s32 *)>rx_buf[adc->bufi];
+
+   stm32_dfsdm_process_data(adc, buffer);
 
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
   pf->timestamp);
@@ -806,8 +832,6 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
 {
struct iio_dev *indio_dev = data;
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
-   struct stm32_dfsdm_filter *fl = >dfsdm->fl_list[adc->fl_id];
-   struct stm32_dfsdm_filter_osr *flo = >flo;
int available = stm32_dfsdm_adc_dma_residue(adc);
size_t old_pos;
 
@@ -832,16 +856,7 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
while (available >= indio_dev->scan_bytes) {
s32 *buffer = (s32 *)>rx_buf[adc->bufi];
 
-   /* Mask 8 LSB that contains the channel ID */
-   *buffer &= 0xFF00;
-   /* Convert 2^(n-1) sample to 2^(n-1)-1 to avoid wrap-around */
-   if (*buffer > flo->max)
-   *buffer -= 1;
-   /*
-* Samples from filter are retrieved with 23 bits resolution
-* or less. Shift left to align MSB on 24 bits.
-*/
-   *buffer <<= flo->lshift;
+   stm32_dfsdm_process_data(adc, buffer);
 
available -= indio_dev->scan_bytes;
adc->bufi += indio_dev->scan_bytes;
-- 
2.7.4



[PATCH 1/5] iio: adc: stm32-dfsdm: fix output resolution

2019-06-19 Thread Olivier Moysan
In buffered mode, output samples are shifted left
unconditionally. This works for filter order 3,
but this shift is not adapted for other filter orders.
Compute required shift, left or right, and shift
output data accordingly.
Add also saturation management to avoid wrap-around
when maximum positive sample is reached.

Fixes: eca949800d2d ("IIO: ADC: add stm32 DFSDM support for PDM microphone")

Signed-off-by: Olivier Moysan 
---
 drivers/iio/adc/stm32-dfsdm-adc.c | 158 +-
 drivers/iio/adc/stm32-dfsdm.h |  24 --
 2 files changed, 142 insertions(+), 40 deletions(-)

diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c 
b/drivers/iio/adc/stm32-dfsdm-adc.c
index 588907cc3b6b..cb596f104919 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -39,9 +39,16 @@
 #define DFSDM_MAX_INT_OVERSAMPLING 256
 #define DFSDM_MAX_FL_OVERSAMPLING 1024
 
-/* Max sample resolutions */
-#define DFSDM_MAX_RES BIT(31)
-#define DFSDM_DATA_RES BIT(23)
+/* Limit filter output resolution to 31 bits. (i.e. sample range is +/-2^30) */
+#define DFSDM_DATA_MAX BIT(30)
+/*
+ * Data are output as two's complement data in a 24 bit field.
+ * Data from filters are in the range +/-2^(n-1)
+ * 2^(n-1) maximum positive value cannot be coded in 2's complement n bits
+ * An extra bit is required to avoid wrap-around of the binary code for 2^(n-1)
+ * So, the resolution of samples from filter is actually limited to 23 bits
+ */
+#define DFSDM_DATA_RES 24
 
 /* Filter configuration */
 #define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \
@@ -181,14 +188,15 @@ static int stm32_dfsdm_get_jextsel(struct iio_dev 
*indio_dev,
return -EINVAL;
 }
 
-static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
-   unsigned int fast, unsigned int oversamp)
+static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl,
+   unsigned int fast, unsigned int oversamp)
 {
unsigned int i, d, fosr, iosr;
-   u64 res;
-   s64 delta;
+   u64 res, max;
+   int bits, shift;
unsigned int m = 1; /* multiplication factor */
unsigned int p = fl->ford;  /* filter order (ford) */
+   struct stm32_dfsdm_filter_osr *flo = >flo;
 
pr_debug("%s: Requested oversampling: %d\n",  __func__, oversamp);
/*
@@ -207,11 +215,9 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter 
*fl,
 
/*
 * Look for filter and integrator oversampling ratios which allows
-* to reach 24 bits data output resolution.
-* Leave as soon as if exact resolution if reached.
-* Otherwise the higher resolution below 32 bits is kept.
+* to maximize data output resolution.
 */
-   fl->res = 0;
+   flo->res = 0;
for (fosr = 1; fosr <= DFSDM_MAX_FL_OVERSAMPLING; fosr++) {
for (iosr = 1; iosr <= DFSDM_MAX_INT_OVERSAMPLING; iosr++) {
if (fast)
@@ -236,32 +242,68 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter 
*fl,
res = fosr;
for (i = p - 1; i > 0; i--) {
res = res * (u64)fosr;
-   if (res > DFSDM_MAX_RES)
+   if (res > DFSDM_DATA_MAX)
break;
}
-   if (res > DFSDM_MAX_RES)
+   if (res > DFSDM_DATA_MAX)
continue;
+
res = res * (u64)m * (u64)iosr;
-   if (res > DFSDM_MAX_RES)
+   if (res > DFSDM_DATA_MAX)
continue;
 
-   delta = res - DFSDM_DATA_RES;
-
-   if (res >= fl->res) {
-   fl->res = res;
-   fl->fosr = fosr;
-   fl->iosr = iosr;
-   fl->fast = fast;
-   pr_debug("%s: fosr = %d, iosr = %d\n",
-__func__, fl->fosr, fl->iosr);
+   if (res >= flo->res) {
+   flo->res = res;
+   flo->fosr = fosr;
+   flo->iosr = iosr;
+
+   bits = fls(flo->res);
+   /* 8 LBSs in data register contain chan info */
+   max = flo->res << 8;
+
+   /* if resolution is not a power of two */
+   if (flo->res > BIT(bits - 1))
+   bits++;
+

[PATCH 0/5] iio: adc: stm32-dfsdm: fix and improve output data managementiio: adc: stm32-dfsdm: fix and improve output data management

2019-06-19 Thread Olivier Moysan
This patch-set provides some fixes and improvements regarding output data format
for STM32 DFSDM.
- Fix output data resolution and saturation management in continuous mode
- Fix data type
- Apply same processing on data in continuous and triggered mode
- Add fast mode support to get better resolution for output data
- Add a comment about 16 bits data transfers

Olivier Moysan (5):
  iio: adc: stm32-dfsdm: fix output resolution
  iio: adc: stm32-dfsdm: fix data type
  iio: adc: stm32-dfsdm: manage data resolution in trigger mode
  iio: adc: stm32-dfsdm: add fast mode support
  iio: adc: stm32-dfsdm: add comment for 16 bits record

 drivers/iio/adc/stm32-dfsdm-adc.c | 233 +++---
 drivers/iio/adc/stm32-dfsdm.h |  24 +++-
 2 files changed, 208 insertions(+), 49 deletions(-)

-- 
2.7.4



[PATCH] ASoC: stm32: dfsdm: add 16 bits audio record support

2019-06-19 Thread Olivier Moysan
Add support of audio 16 bits format record to STM32
DFSDM driver.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_adfsdm.c | 49 +++-
 1 file changed, 39 insertions(+), 10 deletions(-)

diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index cc517e007039..3c9a9deec9af 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -45,7 +45,7 @@ struct stm32_adfsdm_priv {
 static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE,
-   .formats = SNDRV_PCM_FMTBIT_S32_LE,
+   .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
 
.rate_min = 8000,
.rate_max = 32000,
@@ -141,7 +141,8 @@ static const struct snd_soc_dai_driver stm32_adfsdm_dai = {
.capture = {
.channels_min = 1,
.channels_max = 1,
-   .formats = SNDRV_PCM_FMTBIT_S32_LE,
+   .formats = SNDRV_PCM_FMTBIT_S16_LE |
+  SNDRV_PCM_FMTBIT_S32_LE,
.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  SNDRV_PCM_RATE_32000),
},
@@ -152,30 +153,58 @@ static const struct snd_soc_component_driver 
stm32_adfsdm_dai_component = {
.name = "stm32_dfsdm_audio",
 };
 
+static void memcpy_32to16(void *dest, const void *src, size_t n)
+{
+   unsigned int i = 0;
+   u16 *d = (u16 *)dest, *s = (u16 *)src;
+
+   s++;
+   for (i = n; i > 0; i--) {
+   *d++ = *s++;
+   s++;
+   }
+}
+
 static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
 {
struct stm32_adfsdm_priv *priv = private;
struct snd_soc_pcm_runtime *rtd = priv->substream->private_data;
u8 *pcm_buff = priv->pcm_buff;
u8 *src_buff = (u8 *)data;
-   unsigned int buff_size = snd_pcm_lib_buffer_bytes(priv->substream);
-   unsigned int period_size = snd_pcm_lib_period_bytes(priv->substream);
unsigned int old_pos = priv->pos;
-   unsigned int cur_size = size;
+   size_t buff_size = snd_pcm_lib_buffer_bytes(priv->substream);
+   size_t period_size = snd_pcm_lib_period_bytes(priv->substream);
+   size_t cur_size, src_size = size;
+   snd_pcm_format_t format = priv->substream->runtime->format;
+
+   if (format == SNDRV_PCM_FORMAT_S16_LE)
+   src_size >>= 1;
+   cur_size = src_size;
 
dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n",
-   __func__, _buff[priv->pos], priv->pos, size);
+   __func__, _buff[priv->pos], priv->pos, src_size);
 
-   if ((priv->pos + size) > buff_size) {
-   memcpy(_buff[priv->pos], src_buff, buff_size - priv->pos);
+   if ((priv->pos + src_size) > buff_size) {
+   if (format == SNDRV_PCM_FORMAT_S16_LE)
+   memcpy_32to16(_buff[priv->pos], src_buff,
+ buff_size - priv->pos);
+   else
+   memcpy(_buff[priv->pos], src_buff,
+  buff_size - priv->pos);
cur_size -= buff_size - priv->pos;
priv->pos = 0;
}
 
-   memcpy(_buff[priv->pos], _buff[size - cur_size], cur_size);
+   if (format == SNDRV_PCM_FORMAT_S16_LE)
+   memcpy_32to16(_buff[priv->pos],
+ _buff[src_size - cur_size], cur_size);
+   else
+   memcpy(_buff[priv->pos], _buff[src_size - cur_size],
+  cur_size);
+
priv->pos = (priv->pos + cur_size) % buff_size;
 
-   if (cur_size != size || (old_pos && (old_pos % period_size < size)))
+   if (cur_size != src_size || (old_pos && (old_pos % period_size < size)))
snd_pcm_period_elapsed(priv->substream);
 
return 0;
-- 
2.7.4



[PATCH] ARM: dts: stm32: add sai id registers to stm32mp157c

2019-06-11 Thread Olivier Moysan
Add identification registers to address range
of SAI DT parent node, for stm32mp157c.

Change-Id: I696363794fab59ba8d7869b3ffbc041dacdf28de
Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157c.dtsi | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi 
b/arch/arm/boot/dts/stm32mp157c.dtsi
index e98aad37ff9e..0c4e6ebc3529 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -746,7 +746,7 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x4400a000 0x400>;
-   reg = <0x4400a000 0x4>;
+   reg = <0x4400a000 0x4>, <0x4400a3f0 0x10>;
interrupts = ;
resets = < SAI1_R>;
status = "disabled";
@@ -778,7 +778,7 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x4400b000 0x400>;
-   reg = <0x4400b000 0x4>;
+   reg = <0x4400b000 0x4>, <0x4400b3f0 0x10>;
interrupts = ;
resets = < SAI2_R>;
status = "disabled";
@@ -809,7 +809,7 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x4400c000 0x400>;
-   reg = <0x4400c000 0x4>;
+   reg = <0x4400c000 0x4>, <0x4400c3f0 0x10>;
interrupts = ;
resets = < SAI3_R>;
status = "disabled";
@@ -1164,7 +1164,7 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x50027000 0x400>;
-   reg = <0x50027000 0x4>;
+   reg = <0x50027000 0x4>, <0x500273f0 0x10>;
interrupts = ;
resets = < SAI4_R>;
status = "disabled";
-- 
2.7.4



[PATCH] ASoC: stm32: sai: manage identification registers

2019-06-03 Thread Olivier Moysan
Add support of identification registers in STM32 SAI.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai.c | 44 +++
 sound/soc/stm/stm32_sai.h | 54 ---
 sound/soc/stm/stm32_sai_sub.c | 14 ++-
 3 files changed, 88 insertions(+), 24 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 7550d5f08be3..98b29f712831 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -30,13 +30,20 @@
 #include "stm32_sai.h"
 
 static const struct stm32_sai_conf stm32_sai_conf_f4 = {
-   .version = SAI_STM32F4,
-   .has_spdif = false,
+   .version = STM_SAI_STM32F4,
+   .fifo_size = 8,
+   .has_spdif_pdm = false,
 };
 
+/*
+ * Default settings for stm32 H7 socs and next.
+ * These default settings will be overridden if the soc provides
+ * support of hardware configuration registers.
+ */
 static const struct stm32_sai_conf stm32_sai_conf_h7 = {
-   .version = SAI_STM32H7,
-   .has_spdif = true,
+   .version = STM_SAI_STM32H7,
+   .fifo_size = 8,
+   .has_spdif_pdm = true,
 };
 
 static const struct of_device_id stm32_sai_ids[] = {
@@ -157,6 +164,8 @@ static int stm32_sai_probe(struct platform_device *pdev)
struct reset_control *rst;
struct resource *res;
const struct of_device_id *of_id;
+   u32 val;
+   int ret;
 
sai = devm_kzalloc(>dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
@@ -169,7 +178,8 @@ static int stm32_sai_probe(struct platform_device *pdev)
 
of_id = of_match_device(stm32_sai_ids, >dev);
if (of_id)
-   sai->conf = (struct stm32_sai_conf *)of_id->data;
+   memcpy(>conf, (const struct stm32_sai_conf *)of_id->data,
+  sizeof(struct stm32_sai_conf));
else
return -EINVAL;
 
@@ -208,6 +218,30 @@ static int stm32_sai_probe(struct platform_device *pdev)
reset_control_deassert(rst);
}
 
+   /* Enable peripheral clock to allow register access */
+   ret = clk_prepare_enable(sai->pclk);
+   if (ret) {
+   dev_err(>dev, "failed to enable clock: %d\n", ret);
+   return ret;
+   }
+
+   val = FIELD_GET(SAI_IDR_ID_MASK,
+   readl_relaxed(sai->base + STM_SAI_IDR));
+   if (val == SAI_IPIDR_NUMBER) {
+   val = readl_relaxed(sai->base + STM_SAI_HWCFGR);
+   sai->conf.fifo_size = FIELD_GET(SAI_HWCFGR_FIFO_SIZE, val);
+   sai->conf.has_spdif_pdm = !!FIELD_GET(SAI_HWCFGR_SPDIF_PDM,
+ val);
+
+   val = readl_relaxed(sai->base + STM_SAI_VERR);
+   sai->conf.version = val;
+
+   dev_dbg(>dev, "SAI version: %lu.%lu registered\n",
+   FIELD_GET(SAI_VERR_MAJ_MASK, val),
+   FIELD_GET(SAI_VERR_MIN_MASK, val));
+   }
+   clk_disable_unprepare(sai->pclk);
+
sai->pdev = pdev;
sai->set_sync = _sai_set_sync;
platform_set_drvdata(pdev, sai);
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 9c36a393ab7b..158c73f557f7 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -37,6 +37,12 @@
 #define STM_SAI_PDMCR_REGX 0x40
 #define STM_SAI_PDMLY_REGX 0x44
 
+/* Hardware configuration registers */
+#define STM_SAI_HWCFGR 0x3F0
+#define STM_SAI_VERR   0x3F4
+#define STM_SAI_IDR0x3F8
+#define STM_SAI_SIDR   0x3FC
+
 / Bit definition for SAI_GCR register ***/
 #define SAI_GCR_SYNCIN_SHIFT   0
 #define SAI_GCR_SYNCIN_WDTH2
@@ -82,7 +88,7 @@
 #define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT)
 
 #define SAI_XCR1_MCKDIV_SHIFT  20
-#define SAI_XCR1_MCKDIV_WIDTH(x)   (((x) == SAI_STM32F4) ? 4 : 6)
+#define SAI_XCR1_MCKDIV_WIDTH(x)   (((x) == STM_SAI_STM32F4) ? 4 : 6)
 #define SAI_XCR1_MCKDIV_MASK(x) GENMASK((SAI_XCR1_MCKDIV_SHIFT + (x) - 1),\
SAI_XCR1_MCKDIV_SHIFT)
 #define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT)
@@ -234,8 +240,33 @@
 #define SAI_PDMDLY_4R_MASK GENMASK(30, SAI_PDMDLY_4R_SHIFT)
 #define SAI_PDMDLY_4R_WIDTH3
 
-#define STM_SAI_IS_F4(ip)  ((ip)->conf->version == SAI_STM32F4)
-#define STM_SAI_IS_H7(ip)  ((ip)->conf->version == SAI_STM32H7)
+/* Registers below apply to SAI version 2.1 and more */
+
+/* Bit definition for SAI_HWCFGR register */
+#define SAI_HWCFGR_FIFO_SIZE   GENMASK(7, 0)
+#define SAI_HWCFGR_SPDIF_PDM   GENMASK(11, 8)
+#define SAI_HWCFGR_REGOUT  GENMASK(19, 12)
+
+/* Bit definition for SAI_VERR register */
+#define SAI_VERR_MIN_MASK  GENMASK(3, 0)
+#define SAI_VERR_MAJ_MASK  GENMASK(7, 4)
+
+/* Bit definition for SAI_ID

[PATCH 1/2] ASoC: stm32: i2s: update pcm hardware constraints

2019-05-06 Thread Olivier Moysan
- Set period minimum size. Ensure at least 5ms period
up to 48kHz/16 bits to prevent underrun/overrun.
- Remove MDMA constraints on period maximum size and
set period maximum to half the buffer maximum size.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 97d5e9901a0e..8ee697ff1f86 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -731,7 +731,8 @@ static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = 
{
 static const struct snd_pcm_hardware stm32_i2s_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
.buffer_bytes_max = 8 * PAGE_SIZE,
-   .period_bytes_max = 2048,
+   .period_bytes_min = 1024,
+   .period_bytes_max = 4 * PAGE_SIZE,
.periods_min = 2,
.periods_max = 8,
 };
-- 
2.7.4



[PATCH 0/2] ASoC: stm32: i2s: add some features

2019-05-06 Thread Olivier Moysan
Update and add some features in STM32 I2S driver.
- update pcm hardware constraints
- add management of identification registers

Olivier Moysan (2):
  ASoC: stm32: i2s: update pcm hardware constraints
  ASoC: stm32: i2s: manage identification registers

 sound/soc/stm/stm32_i2s.c | 63 ---
 1 file changed, 59 insertions(+), 4 deletions(-)

-- 
2.7.4



[PATCH 2/2] ASoC: stm32: i2s: manage identification registers

2019-05-06 Thread Olivier Moysan
Add support of identification registers in STM32 I2S.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 60 ---
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 8ee697ff1f86..8846f49b2951 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -37,6 +38,10 @@
 #define STM32_I2S_TXDR_REG 0X20
 #define STM32_I2S_RXDR_REG 0x30
 #define STM32_I2S_CGFR_REG 0X50
+#define STM32_I2S_HWCFGR_REG   0x3F0
+#define STM32_I2S_VERR_REG 0x3F4
+#define STM32_I2S_IPIDR_REG0x3F8
+#define STM32_I2S_SIDR_REG 0x3FC
 
 /* Bit definition for SPI2S_CR1 register */
 #define I2S_CR1_SPEBIT(0)
@@ -143,6 +148,23 @@
 #define I2S_CGFR_ODD   BIT(I2S_CGFR_ODD_SHIFT)
 #define I2S_CGFR_MCKOE BIT(25)
 
+/* Registers below apply to I2S version 1.1 and more */
+
+/* Bit definition for SPI_HWCFGR register */
+#define I2S_HWCFGR_I2S_SUPPORT_MASKGENMASK(15, 12)
+
+/* Bit definition for SPI_VERR register */
+#define I2S_VERR_MIN_MASK  GENMASK(3, 0)
+#define I2S_VERR_MAJ_MASK  GENMASK(7, 4)
+
+/* Bit definition for SPI_IPIDR register */
+#define I2S_IPIDR_ID_MASK  GENMASK(31, 0)
+
+/* Bit definition for SPI_SIDR register */
+#define I2S_SIDR_ID_MASK   GENMASK(31, 0)
+
+#define I2S_IPIDR_NUMBER   0x00130022
+
 enum i2s_master_mode {
I2S_MS_NOT_SET,
I2S_MS_MASTER,
@@ -280,6 +302,10 @@ static bool stm32_i2s_readable_reg(struct device *dev, 
unsigned int reg)
case STM32_I2S_SR_REG:
case STM32_I2S_RXDR_REG:
case STM32_I2S_CGFR_REG:
+   case STM32_I2S_HWCFGR_REG:
+   case STM32_I2S_VERR_REG:
+   case STM32_I2S_IPIDR_REG:
+   case STM32_I2S_SIDR_REG:
return true;
default:
return false;
@@ -711,10 +737,11 @@ static const struct regmap_config 
stm32_h7_i2s_regmap_conf = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
-   .max_register = STM32_I2S_CGFR_REG,
+   .max_register = STM32_I2S_SIDR_REG,
.readable_reg = stm32_i2s_readable_reg,
.volatile_reg = stm32_i2s_volatile_reg,
.writeable_reg = stm32_i2s_writeable_reg,
+   .num_reg_defaults_raw = STM32_I2S_SIDR_REG / sizeof(u32) + 1,
.fast_io = true,
.cache_type = REGCACHE_FLAT,
 };
@@ -865,6 +892,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
 static int stm32_i2s_probe(struct platform_device *pdev)
 {
struct stm32_i2s_data *i2s;
+   u32 val;
int ret;
 
i2s = devm_kzalloc(>dev, sizeof(*i2s), GFP_KERNEL);
@@ -903,8 +931,34 @@ static int stm32_i2s_probe(struct platform_device *pdev)
return ret;
 
/* Set SPI/I2S in i2s mode */
-   return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
- I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD);
+   ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG,
+I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD);
+   if (ret)
+   return ret;
+
+   ret = regmap_read(i2s->regmap, STM32_I2S_IPIDR_REG, );
+   if (ret)
+   return ret;
+
+   if (val == I2S_IPIDR_NUMBER) {
+   ret = regmap_read(i2s->regmap, STM32_I2S_HWCFGR_REG, );
+   if (ret)
+   return ret;
+
+   if (!FIELD_GET(I2S_HWCFGR_I2S_SUPPORT_MASK, val)) {
+   dev_err(>dev,
+   "Device does not support i2s mode\n");
+   return -EPERM;
+   }
+
+   ret = regmap_read(i2s->regmap, STM32_I2S_VERR_REG, );
+
+   dev_dbg(>dev, "I2S version: %lu.%lu registered\n",
+   FIELD_GET(I2S_VERR_MAJ_MASK, val),
+   FIELD_GET(I2S_VERR_MIN_MASK, val));
+   }
+
+   return ret;
 }
 
 MODULE_DEVICE_TABLE(of, stm32_i2s_ids);
-- 
2.7.4



[PATCH 2/3] ASoC: stm32: spdifrx: change trace level on iec control

2019-05-06 Thread Olivier Moysan
Change trace level to debug to avoid spurious messages.
Return quietly when accessing iec958 control, while no
S/PDIF signal is available.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_spdifrx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index aa83b50efabb..3d64200edbb5 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -496,7 +496,7 @@ static int stm32_spdifrx_get_ctrl_data(struct 
stm32_spdifrx_data *spdifrx)
if (wait_for_completion_interruptible_timeout(>cs_completion,
  msecs_to_jiffies(100))
  <= 0) {
-   dev_err(>pdev->dev, "Failed to get control data\n");
+   dev_dbg(>pdev->dev, "Failed to get control data\n");
ret = -EAGAIN;
}
 
-- 
2.7.4



[PATCH 3/3] ASoC: stm32: spdifrx: manage identification registers

2019-05-06 Thread Olivier Moysan
Add support of identification registers in STM32 SPDIFRX.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_spdifrx.c | 37 +++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 3d64200edbb5..4a3fad4a711f 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -16,6 +16,7 @@
  * details.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -36,6 +37,9 @@
 #define STM32_SPDIFRX_DR   0x10
 #define STM32_SPDIFRX_CSR  0x14
 #define STM32_SPDIFRX_DIR  0x18
+#define STM32_SPDIFRX_VERR 0x3F4
+#define STM32_SPDIFRX_IDR  0x3F8
+#define STM32_SPDIFRX_SIDR 0x3FC
 
 /* Bit definition for SPDIF_CR register */
 #define SPDIFRX_CR_SPDIFEN_SHIFT   0
@@ -169,6 +173,18 @@
 #define SPDIFRX_SPDIFEN_SYNC   0x1
 #define SPDIFRX_SPDIFEN_ENABLE 0x3
 
+/* Bit definition for SPDIFRX_VERR register */
+#define SPDIFRX_VERR_MIN_MASK  GENMASK(3, 0)
+#define SPDIFRX_VERR_MAJ_MASK  GENMASK(7, 4)
+
+/* Bit definition for SPDIFRX_IDR register */
+#define SPDIFRX_IDR_ID_MASKGENMASK(31, 0)
+
+/* Bit definition for SPDIFRX_SIDR register */
+#define SPDIFRX_SIDR_SID_MASK  GENMASK(31, 0)
+
+#define SPDIFRX_IPIDR_NUMBER   0x00130041
+
 #define SPDIFRX_IN10x1
 #define SPDIFRX_IN20x2
 #define SPDIFRX_IN30x3
@@ -607,6 +623,9 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, 
unsigned int reg)
case STM32_SPDIFRX_DR:
case STM32_SPDIFRX_CSR:
case STM32_SPDIFRX_DIR:
+   case STM32_SPDIFRX_VERR:
+   case STM32_SPDIFRX_IDR:
+   case STM32_SPDIFRX_SIDR:
return true;
default:
return false;
@@ -642,10 +661,11 @@ static const struct regmap_config 
stm32_h7_spdifrx_regmap_conf = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
-   .max_register = STM32_SPDIFRX_DIR,
+   .max_register = STM32_SPDIFRX_SIDR,
.readable_reg = stm32_spdifrx_readable_reg,
.volatile_reg = stm32_spdifrx_volatile_reg,
.writeable_reg = stm32_spdifrx_writeable_reg,
+   .num_reg_defaults_raw = STM32_SPDIFRX_SIDR / sizeof(u32) + 1,
.fast_io = true,
.cache_type = REGCACHE_FLAT,
 };
@@ -912,6 +932,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
struct stm32_spdifrx_data *spdifrx;
struct reset_control *rst;
const struct snd_dmaengine_pcm_config *pcm_config = NULL;
+   u32 ver, idr;
int ret;
 
spdifrx = devm_kzalloc(>dev, sizeof(*spdifrx), GFP_KERNEL);
@@ -968,7 +989,19 @@ static int stm32_spdifrx_probe(struct platform_device 
*pdev)
goto error;
}
 
-   return 0;
+   ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, );
+   if (ret)
+   goto error;
+
+   if (idr == SPDIFRX_IPIDR_NUMBER) {
+   ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, );
+
+   dev_dbg(>dev, "SPDIFRX version: %lu.%lu registered\n",
+   FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver),
+   FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver));
+   }
+
+   return ret;
 
 error:
if (!IS_ERR(spdifrx->ctrl_chan))
-- 
2.7.4



[PATCH 1/3] ASoC: stm32: spdifrx: update pcm hardware constraints

2019-05-06 Thread Olivier Moysan
- Set period minimum size. Ensure at least 5ms period
up to 48kHz/16 bits to prevent underrun/overrun.
- Remove MDMA constraints on period maximum size and
set period maximum to half the buffer maximum size.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_spdifrx.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index b4c3d983e195..aa83b50efabb 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -845,7 +845,8 @@ static struct snd_soc_dai_driver stm32_spdifrx_dai[] = {
 static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
.buffer_bytes_max = 8 * PAGE_SIZE,
-   .period_bytes_max = 2048, /* MDMA constraint */
+   .period_bytes_min = 1024,
+   .period_bytes_max = 4 * PAGE_SIZE,
.periods_min = 2,
.periods_max = 8,
 };
-- 
2.7.4



[PATCH 0/3] ASoC: stm32: spdifrx: add some features

2019-05-06 Thread Olivier Moysan
Update and add some features in STM32 SPDIFRX driver.
- pdate pcm hardware constraints
- change trace level on iec control
- add management of identification registers

Olivier Moysan (3):
  ASoC: stm32: spdifrx: update pcm hardware constraints
  ASoC: stm32: spdifrx: change trace level on iec control
  ASoC: stm32: spdifrx: manage identification registers

 sound/soc/stm/stm32_spdifrx.c | 42 ++
 1 file changed, 38 insertions(+), 4 deletions(-)

-- 
2.7.4



[Linux-stm32][PATCH 0/4] ARM: dts: stm32: add i2s and sai support on stm32mp157c

2019-04-25 Thread Olivier Moysan
This patchset adds support of STM32 SAI and I2S on stm32mp157c

Olivier Moysan (4):
  ARM: dts: stm32: add sai support on stm32mp157c
  ARM: dts: stm32: add sai pins muxing on stm32mp157
  ARM: dts: stm32: add i2s support on stm32mp157c
  ARM: dts: stm32: add i2s pins muxing on stm32mp157

 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi |  92 +
 arch/arm/boot/dts/stm32mp157c.dtsi| 158 ++
 2 files changed, 250 insertions(+)

-- 
2.7.4



[Linux-stm32][PATCH 1/4] ARM: dts: stm32: add sai support on stm32mp157c

2019-04-25 Thread Olivier Moysan
This patch adds support of STM32 SAI on stm32mp157c.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157c.dtsi | 125 +
 1 file changed, 125 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi 
b/arch/arm/boot/dts/stm32mp157c.dtsi
index 2afeee65c3ea..9ae40240f635 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -708,6 +708,100 @@
status = "disabled";
};
 
+   sai1: sai@4400a000 {
+   compatible = "st,stm32h7-sai";
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges = <0 0x4400a000 0x400>;
+   reg = <0x4400a000 0x4>;
+   interrupts = ;
+   resets = < SAI1_R>;
+   status = "disabled";
+
+   sai1a: audio-controller@4400a004 {
+   #sound-dai-cells = <0>;
+
+   compatible = "st,stm32-sai-sub-a";
+   reg = <0x4 0x1c>;
+   clocks = < SAI1_K>;
+   clock-names = "sai_ck";
+   dmas = < 87 0x400 0x01>;
+   status = "disabled";
+   };
+
+   sai1b: audio-controller@4400a024 {
+   #sound-dai-cells = <0>;
+   compatible = "st,stm32-sai-sub-b";
+   reg = <0x24 0x1c>;
+   clocks = < SAI1_K>;
+   clock-names = "sai_ck";
+   dmas = < 88 0x400 0x01>;
+   status = "disabled";
+   };
+   };
+
+   sai2: sai@4400b000 {
+   compatible = "st,stm32h7-sai";
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges = <0 0x4400b000 0x400>;
+   reg = <0x4400b000 0x4>;
+   interrupts = ;
+   resets = < SAI2_R>;
+   status = "disabled";
+
+   sai2a: audio-controller@4400b004 {
+   #sound-dai-cells = <0>;
+   compatible = "st,stm32-sai-sub-a";
+   reg = <0x4 0x1c>;
+   clocks = < SAI2_K>;
+   clock-names = "sai_ck";
+   dmas = < 89 0x400 0x01>;
+   status = "disabled";
+   };
+
+   sai2b: audio-controller@4400b024 {
+   #sound-dai-cells = <0>;
+   compatible = "st,stm32-sai-sub-b";
+   reg = <0x24 0x1c>;
+   clocks = < SAI2_K>;
+   clock-names = "sai_ck";
+   dmas = < 90 0x400 0x01>;
+   status = "disabled";
+   };
+   };
+
+   sai3: sai@4400c000 {
+   compatible = "st,stm32h7-sai";
+   #address-cells = <1>;
+   #size-cells = <1>;
+   ranges = <0 0x4400c000 0x400>;
+   reg = <0x4400c000 0x4>;
+   interrupts = ;
+   resets = < SAI3_R>;
+   status = "disabled";
+
+   sai3a: audio-controller@4400c004 {
+   #sound-dai-cells = <0>;
+   compatible = "st,stm32-sai-sub-a";
+   reg = <0x04 0x1c>;
+   clocks = < SAI3_K>;
+   clock-names = "sai_ck";
+   dmas = < 113 0x400 0x01>;
+   status = "disabled";
+   };
+
+   sai3b: audio-controller@4400c024 {
+   #sound-dai-cells = <0>;
+   compatible = "st,stm32-sai-sub-b";
+   reg = <0x24 0x1c>;
+   clocks = < SAI3_K>;
+   clock-names = "sai_ck";
+

[Linux-stm32][PATCH 4/4] ARM: dts: stm32: add i2s pins muxing on stm32mp157

2019-04-25 Thread Olivier Moysan
Add I2S pins muxing to stm32mp157.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 6ea9b9ff45e7..e29bf7a2c18a 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -276,6 +276,25 @@
};
};
 
+   i2s2_pins_a: i2s2-0 {
+   pins {
+   pinmux = , 
/* I2S2_SDO */
+, 
/* I2S2_WS */
+; 
/* I2S2_CK */
+   slew-rate = <1>;
+   drive-push-pull;
+   bias-disable;
+   };
+   };
+
+   i2s2_pins_sleep_a: i2s2-1 {
+   pins {
+   pinmux = , /* I2S2_SDO */
+, /* I2S2_WS */
+; /* I2S2_CK */
+   };
+   };
+
ltdc_pins_a: ltdc-a-0 {
pins {
pinmux = , 
/* LCD_CLK */
-- 
2.7.4



[Linux-stm32][PATCH 3/4] ARM: dts: stm32: add i2s support on stm32mp157c

2019-04-25 Thread Olivier Moysan
This patch adds support of STM32 I2S on stm32mp157c.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157c.dtsi | 33 +
 1 file changed, 33 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi 
b/arch/arm/boot/dts/stm32mp157c.dtsi
index 9ae40240f635..ec2d6475caa2 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -365,6 +365,17 @@
status = "disabled";
};
 
+   i2s2: audio-controller@4000b000 {
+   compatible = "st,stm32h7-i2s";
+   #sound-dai-cells = <0>;
+   reg = <0x4000b000 0x400>;
+   interrupts = ;
+   dmas = < 39 0x400 0x01>,
+  < 40 0x400 0x01>;
+   dma-names = "rx", "tx";
+   status = "disabled";
+   };
+
spi3: spi@4000c000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -379,6 +390,17 @@
status = "disabled";
};
 
+   i2s3: audio-controller@4000c000 {
+   compatible = "st,stm32h7-i2s";
+   #sound-dai-cells = <0>;
+   reg = <0x4000c000 0x400>;
+   interrupts = ;
+   dmas = < 61 0x400 0x01>,
+  < 62 0x400 0x01>;
+   dma-names = "rx", "tx";
+   status = "disabled";
+   };
+
spdifrx: audio-controller@4000d000 {
compatible = "st,stm32h7-spdifrx";
#sound-dai-cells = <0>;
@@ -607,6 +629,17 @@
status = "disabled";
};
 
+   i2s1: audio-controller@44004000 {
+   compatible = "st,stm32h7-i2s";
+   #sound-dai-cells = <0>;
+   reg = <0x44004000 0x400>;
+   interrupts = ;
+   dmas = < 37 0x400 0x01>,
+  < 38 0x400 0x01>;
+   dma-names = "rx", "tx";
+   status = "disabled";
+   };
+
spi4: spi@44005000 {
#address-cells = <1>;
#size-cells = <0>;
-- 
2.7.4



[Linux-stm32][PATCH 2/4] ARM: dts: stm32: add sai pins muxing on stm32mp157

2019-04-25 Thread Olivier Moysan
Add SAI pins muxing to stm32mp157.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 73 +++
 1 file changed, 73 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 85c417d9983b..6ea9b9ff45e7 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -506,6 +506,79 @@
};
};
 
+   sai2a_pins_a: sai2a-0 {
+   pins {
+   pinmux = , 
/* SAI2_SCK_A */
+, 
/* SAI2_SD_A */
+, 
/* SAI2_FS_A */
+; 
/* SAI2_MCLK_A */
+   slew-rate = <0>;
+   drive-push-pull;
+   bias-disable;
+   };
+   };
+
+   sai2a_sleep_pins_a: sai2a-1 {
+   pins {
+   pinmux = , /* SAI2_SCK_A */
+, /* SAI2_SD_A */
+, /* SAI2_FS_A */
+; /* SAI2_MCLK_A */
+   };
+   };
+
+   sai2b_pins_a: sai2b-0 {
+   pins1 {
+   pinmux = , 
/* SAI2_SCK_B */
+, 
/* SAI2_FS_B */
+; 
/* SAI2_MCLK_B */
+   slew-rate = <0>;
+   drive-push-pull;
+   bias-disable;
+   };
+   pins2 {
+   pinmux = ; 
/* SAI2_SD_B */
+   bias-disable;
+   };
+   };
+
+   sai2b_sleep_pins_a: sai2b-1 {
+   pins {
+   pinmux = , /* SAI2_SD_B */
+, /* SAI2_SCK_B */
+, /* SAI2_FS_B */
+; /* SAI2_MCLK_B */
+   };
+   };
+
+   sai2b_pins_b: sai2b-2 {
+   pins {
+   pinmux = ; 
/* SAI2_SD_B */
+   bias-disable;
+   };
+   };
+
+   sai2b_sleep_pins_b: sai2b-3 {
+   pins {
+   pinmux = ; /* SAI2_SD_B */
+   };
+   };
+
+   sai4a_pins_a: sai4a-0 {
+   pins {
+   pinmux = ; 
/* SAI4_SD_A */
+   slew-rate = <0>;
+   drive-push-pull;
+   bias-disable;
+   };
+   };
+
+   sai4a_sleep_pins_a: sai4a-1 {
+   pins {
+   pinmux = ; /* SAI4_SD_A */
+   };
+   };
+
sdmmc1_b4_pins_a: sdmmc1-b4-0 {
pins {
pinmux = , 
/* SDMMC1_D0 */
-- 
2.7.4



Re: [PATCH] ASoC: stm32: i2s: return the get_irq error

2019-04-25 Thread Olivier MOYSAN


On 4/24/19 5:28 PM, Fabien Dessenne wrote:
> During probe, return the "get_irq" error value instead of -ENOENT. This
> allows the driver to be deferred probed if needed.
> 
> Signed-off-by: Fabien Dessenne 

Acked-by: Olivier Moysan 

> ---
>   sound/soc/stm/stm32_i2s.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
> index 9526342..97d5e99 100644
> --- a/sound/soc/stm/stm32_i2s.c
> +++ b/sound/soc/stm/stm32_i2s.c
> @@ -838,8 +838,9 @@ static int stm32_i2s_parse_dt(struct platform_device 
> *pdev,
>   /* Get irqs */
>   irq = platform_get_irq(pdev, 0);
>   if (irq < 0) {
> - dev_err(>dev, "no irq for node %s\n", pdev->name);
> - return -ENOENT;
> + if (irq != -EPROBE_DEFER)
> + dev_err(>dev, "no irq for node %s\n", pdev->name);
> + return irq;
>   }
>   
>   ret = devm_request_irq(>dev, irq, stm32_i2s_isr, IRQF_ONESHOT,
> 

Re: [PATCH] ASoC: stm32: simplify dai driver initialisation

2019-04-23 Thread Olivier MOYSAN
Hello Arnaud,

On 4/5/19 11:26 AM, Arnaud Pouliquen wrote:
> Suppress the useless dynamic allocation of the dai driver structure.
> 
> Signed-off-by: Arnaud Pouliquen 
> ---
>   sound/soc/stm/stm32_sai_sub.c | 43 
> +--
>   1 file changed, 9 insertions(+), 34 deletions(-)
> 
> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
> index 3dd54bc..e3b021c 100644
> --- a/sound/soc/stm/stm32_sai_sub.c
> +++ b/sound/soc/stm/stm32_sai_sub.c
> @@ -109,7 +109,7 @@ struct stm32_sai_sub_data {
>   struct regmap *regmap;
>   const struct regmap_config *regmap_config;
>   struct snd_dmaengine_dai_dma_data dma_params;
> - struct snd_soc_dai_driver *cpu_dai_drv;
> + struct snd_soc_dai_driver cpu_dai_drv;
>   struct snd_soc_dai *cpu_dai;
>   struct snd_pcm_substream *substream;
>   struct stm32_sai_data *pdata;
> @@ -1204,8 +1204,7 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = 
> {
>   .periods_max = 8,
>   };
>   
> -static struct snd_soc_dai_driver stm32_sai_playback_dai[] = {
> -{
> +static struct snd_soc_dai_driver stm32_sai_playback_dai = {
>   .probe = stm32_sai_dai_probe,
>   .pcm_new = stm32_sai_pcm_new,
>   .id = 1, /* avoid call to fmt_single_name() */
> @@ -1222,11 +1221,9 @@ static struct snd_soc_dai_driver 
> stm32_sai_playback_dai[] = {
>   SNDRV_PCM_FMTBIT_S32_LE,
>   },
>   .ops = _sai_pcm_dai_ops,
> - }
>   };
>   
> -static struct snd_soc_dai_driver stm32_sai_capture_dai[] = {
> -{
> +static struct snd_soc_dai_driver stm32_sai_capture_dai = {
>   .probe = stm32_sai_dai_probe,
>   .id = 1, /* avoid call to fmt_single_name() */
>   .capture = {
> @@ -1242,7 +1239,6 @@ static struct snd_soc_dai_driver 
> stm32_sai_capture_dai[] = {
>   SNDRV_PCM_FMTBIT_S32_LE,
>   },
>   .ops = _sai_pcm_dai_ops,
> - }
>   };
>   
>   static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
> @@ -1411,29 +1407,6 @@ static int stm32_sai_sub_parse_of(struct 
> platform_device *pdev,
>   return 0;
>   }
>   
> -static int stm32_sai_sub_dais_init(struct platform_device *pdev,
> -struct stm32_sai_sub_data *sai)
> -{
> - sai->cpu_dai_drv = devm_kzalloc(>dev,
> - sizeof(struct snd_soc_dai_driver),
> - GFP_KERNEL);
> - if (!sai->cpu_dai_drv)
> - return -ENOMEM;
> -
> - if (STM_SAI_IS_PLAYBACK(sai)) {
> - memcpy(sai->cpu_dai_drv, _sai_playback_dai,
> -sizeof(stm32_sai_playback_dai));
> - sai->cpu_dai_drv->playback.stream_name = sai->cpu_dai_drv->name;
> - } else {
> - memcpy(sai->cpu_dai_drv, _sai_capture_dai,
> -sizeof(stm32_sai_capture_dai));
> - sai->cpu_dai_drv->capture.stream_name = sai->cpu_dai_drv->name;
> - }
> - sai->cpu_dai_drv->name = dev_name(>dev);
> -
> - return 0;
> -}
> -
>   static int stm32_sai_sub_probe(struct platform_device *pdev)
>   {
>   struct stm32_sai_sub_data *sai;
> @@ -1465,9 +1438,11 @@ static int stm32_sai_sub_probe(struct platform_device 
> *pdev)
>   if (ret)
>   return ret;
>   
> - ret = stm32_sai_sub_dais_init(pdev, sai);
> - if (ret)
> - return ret;
> + if (STM_SAI_IS_PLAYBACK(sai))
> + sai->cpu_dai_drv = stm32_sai_playback_dai;
> + else
> + sai->cpu_dai_drv = stm32_sai_capture_dai;
> + sai->cpu_dai_drv.name = dev_name(>dev);
>   
>   ret = devm_request_irq(>dev, sai->pdata->irq, stm32_sai_isr,
>  IRQF_SHARED, dev_name(>dev), sai);
> @@ -1477,7 +1452,7 @@ static int stm32_sai_sub_probe(struct platform_device 
> *pdev)
>   }
>   
>   ret = devm_snd_soc_register_component(>dev, _component,
> -   sai->cpu_dai_drv, 1);
> +   >cpu_dai_drv, 1);
>   if (ret)
>   return ret;
>   
> 

Just one comment. sai is missing in commit message.

Reviewed-by: Olivier Moysan 

BRs
olivier


[PATCH] ASoC: stm32: sai: fix master clock management

2019-04-10 Thread Olivier Moysan
When master clock is used, master clock rate is set exclusively.
Parent clocks of master clock cannot be changed after a call to
clk_set_rate_exclusive(). So the parent clock of SAI kernel clock
must be set before.
Ensure also that exclusive rate operations are balanced
in STM32 SAI driver.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai_sub.c | 64 +++
 1 file changed, 47 insertions(+), 17 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 3dd54bc54fa1..77aa38183955 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -70,6 +70,7 @@
 #define SAI_IEC60958_STATUS_BYTES  24
 
 #define SAI_MCLK_NAME_LEN  32
+#define SAI_RATE_11K   11025
 
 /**
  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
@@ -311,6 +312,25 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data 
*sai,
return ret;
 }
 
+static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai,
+ unsigned int rate)
+{
+   struct platform_device *pdev = sai->pdev;
+   struct clk *parent_clk = sai->pdata->clk_x8k;
+   int ret;
+
+   if (!(rate % SAI_RATE_11K))
+   parent_clk = sai->pdata->clk_x11k;
+
+   ret = clk_set_parent(sai->sai_ck, parent_clk);
+   if (ret)
+   dev_err(>dev, " Error %d setting sai_ck parent clock. %s",
+   ret, ret == -EBUSY ?
+   "Active stream rates conflict\n" : "\n");
+
+   return ret;
+}
+
 static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
  unsigned long *prate)
 {
@@ -492,25 +512,29 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai 
*cpu_dai,
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
 
-   if (dir == SND_SOC_CLOCK_OUT) {
+   if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
 SAI_XCR1_NODIV,
 (unsigned int)~SAI_XCR1_NODIV);
if (ret < 0)
return ret;
 
-   dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
-   sai->mclk_rate = freq;
+   /* If master clock is used, set parent clock now */
+   ret = stm32_sai_set_parent_clock(sai, freq);
+   if (ret)
+   return ret;
 
-   if (sai->sai_mclk) {
-   ret = clk_set_rate_exclusive(sai->sai_mclk,
-sai->mclk_rate);
-   if (ret) {
-   dev_err(cpu_dai->dev,
-   "Could not set mclk rate\n");
-   return ret;
-   }
+   ret = clk_set_rate_exclusive(sai->sai_mclk, freq);
+   if (ret) {
+   dev_err(cpu_dai->dev,
+   ret == -EBUSY ?
+   "Active streams have incompatible rates" :
+   "Could not set mclk rate\n");
+   return ret;
}
+
+   dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
+   sai->mclk_rate = freq;
}
 
return 0;
@@ -917,11 +941,13 @@ static int stm32_sai_configure_clock(struct snd_soc_dai 
*cpu_dai,
int div = 0, cr1 = 0;
int sai_clk_rate, mclk_ratio, den;
unsigned int rate = params_rate(params);
+   int ret;
 
-   if (!(rate % 11025))
-   clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k);
-   else
-   clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
+   if (!sai->sai_mclk) {
+   ret = stm32_sai_set_parent_clock(sai, rate);
+   if (ret)
+   return ret;
+   }
sai_clk_rate = clk_get_rate(sai->sai_ck);
 
if (STM_SAI_IS_F4(sai->pdata)) {
@@ -1080,9 +1106,13 @@ static void stm32_sai_shutdown(struct snd_pcm_substream 
*substream,
regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV,
   SAI_XCR1_NODIV);
 
-   clk_disable_unprepare(sai->sai_ck);
+   /* Release mclk rate only if rate was actually set */
+   if (sai->mclk_rate) {
+   clk_rate_exclusive_put(sai->sai_mclk);
+   sai->mclk_rate = 0;
+   }
 
-   clk_rate_exclusive_put(sai->sai_mclk);
+   clk_disable_unprepare(sai->sai_ck);
 
spin_lock_irqsave(>irq_lock, flags);
sai->substream = NULL;
-- 
2.7.4



Re: [PATCH 5/7] ASoC: cs42l51: change mic bias DAPM

2019-04-04 Thread Olivier MOYSAN
Hello Mark,

There are no routes in cs42l51_routes table using "Mic Bias" widget.

I use this widget in a route defined in audio graph card DT node.
I checked other DTs which are using CS42L51 codec (armada-370-db.dts
kirkwood-openrd-client.dts, kirkwood-openrd-ultimate.dts),but I did not 
find reference to "Mic Bias" widget.
So, my understanding is that the patch should not break the legacy.
If you think this assumption is not correct please let me know.

Regards
Olivier


On 4/4/19 7:47 AM, Mark Brown wrote:
> On Wed, Apr 03, 2019 at 03:23:35PM +0200, Olivier Moysan wrote:
>> Use SND_SOC_DAPM_SUPPLY for mic bias DAPM
>> instead of deprecated SND_SOC_DAPM_MICBIAS.
> 
> There are existing users in mainline, have they all been updated to be
> compatible with this, or verified that they don't need updates?
> 


[PATCH 5/7] ASoC: cs42l51: change mic bias DAPM

2019-04-03 Thread Olivier Moysan
Use SND_SOC_DAPM_SUPPLY for mic bias DAPM
instead of deprecated SND_SOC_DAPM_MICBIAS.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 397b68901d1c..33298a7a8aab 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -206,7 +206,8 @@ static const struct snd_kcontrol_new 
cs42l51_adcr_mux_controls =
SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
 
 static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
-   SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
+   SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1, NULL,
+   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
-- 
2.7.4



[PATCH 6/7] ASoC: cs42l51: add power management

2019-04-03 Thread Olivier Moysan
Add sleep PM callbacks to support system low power modes.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51-i2c.c |   7 ++-
 sound/soc/codecs/cs42l51.c | 122 +
 sound/soc/codecs/cs42l51.h |   2 +
 3 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index 8333dbf18ea2..116221e581ce 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -29,8 +29,6 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c,
struct regmap_config config;
 
config = cs42l51_regmap;
-   config.val_bits = 8;
-   config.reg_bits = 8;
 
return cs42l51_probe(>dev, devm_regmap_init_i2c(i2c, ));
 }
@@ -40,10 +38,15 @@ static int cs42l51_i2c_remove(struct i2c_client *i2c)
return cs42l51_remove(>dev);
 }
 
+static const struct dev_pm_ops cs42l51_pm_ops = {
+   SET_SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume)
+};
+
 static struct i2c_driver cs42l51_i2c_driver = {
.driver = {
.name = "cs42l51",
.of_match_table = cs42l51_of_match,
+   .pm = _pm_ops,
},
.probe = cs42l51_i2c_probe,
.remove = cs42l51_i2c_remove,
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 33298a7a8aab..25f17c0051e4 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -56,6 +56,7 @@ struct cs42l51_private {
enum master_slave_mode func;
struct regulator_bulk_data supplies[ARRAY_SIZE(cs42l51_supply_names)];
struct gpio_desc *reset_gpio;
+   struct regmap *regmap;
 };
 
 #define CS42L51_FORMATS ( \
@@ -576,7 +577,106 @@ static const struct snd_soc_component_driver 
soc_component_device_cs42l51 = {
.non_legacy_dai_naming  = 1,
 };
 
+static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg)
+{
+   switch (reg) {
+   case CS42L51_POWER_CTL1:
+   case CS42L51_MIC_POWER_CTL:
+   case CS42L51_INTF_CTL:
+   case CS42L51_MIC_CTL:
+   case CS42L51_ADC_CTL:
+   case CS42L51_ADC_INPUT:
+   case CS42L51_DAC_OUT_CTL:
+   case CS42L51_DAC_CTL:
+   case CS42L51_ALC_PGA_CTL:
+   case CS42L51_ALC_PGB_CTL:
+   case CS42L51_ADCA_ATT:
+   case CS42L51_ADCB_ATT:
+   case CS42L51_ADCA_VOL:
+   case CS42L51_ADCB_VOL:
+   case CS42L51_PCMA_VOL:
+   case CS42L51_PCMB_VOL:
+   case CS42L51_BEEP_FREQ:
+   case CS42L51_BEEP_VOL:
+   case CS42L51_BEEP_CONF:
+   case CS42L51_TONE_CTL:
+   case CS42L51_AOUTA_VOL:
+   case CS42L51_AOUTB_VOL:
+   case CS42L51_PCM_MIXER:
+   case CS42L51_LIMIT_THRES_DIS:
+   case CS42L51_LIMIT_REL:
+   case CS42L51_LIMIT_ATT:
+   case CS42L51_ALC_EN:
+   case CS42L51_ALC_REL:
+   case CS42L51_ALC_THRES:
+   case CS42L51_NOISE_CONF:
+   case CS42L51_CHARGE_FREQ:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static bool cs42l51_volatile_reg(struct device *dev, unsigned int reg)
+{
+   switch (reg) {
+   case CS42L51_STATUS:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static bool cs42l51_readable_reg(struct device *dev, unsigned int reg)
+{
+   switch (reg) {
+   case CS42L51_CHIP_REV_ID:
+   case CS42L51_POWER_CTL1:
+   case CS42L51_MIC_POWER_CTL:
+   case CS42L51_INTF_CTL:
+   case CS42L51_MIC_CTL:
+   case CS42L51_ADC_CTL:
+   case CS42L51_ADC_INPUT:
+   case CS42L51_DAC_OUT_CTL:
+   case CS42L51_DAC_CTL:
+   case CS42L51_ALC_PGA_CTL:
+   case CS42L51_ALC_PGB_CTL:
+   case CS42L51_ADCA_ATT:
+   case CS42L51_ADCB_ATT:
+   case CS42L51_ADCA_VOL:
+   case CS42L51_ADCB_VOL:
+   case CS42L51_PCMA_VOL:
+   case CS42L51_PCMB_VOL:
+   case CS42L51_BEEP_FREQ:
+   case CS42L51_BEEP_VOL:
+   case CS42L51_BEEP_CONF:
+   case CS42L51_TONE_CTL:
+   case CS42L51_AOUTA_VOL:
+   case CS42L51_AOUTB_VOL:
+   case CS42L51_PCM_MIXER:
+   case CS42L51_LIMIT_THRES_DIS:
+   case CS42L51_LIMIT_REL:
+   case CS42L51_LIMIT_ATT:
+   case CS42L51_ALC_EN:
+   case CS42L51_ALC_REL:
+   case CS42L51_ALC_THRES:
+   case CS42L51_NOISE_CONF:
+   case CS42L51_STATUS:
+   case CS42L51_CHARGE_FREQ:
+   return true;
+   default:
+   return false;
+   }
+}
+
 const struct regmap_config cs42l51_regmap = {
+   .reg_bits = 8,
+   .reg_stride = 1,
+   .val_bits = 8,
+   .use_single_write = true,
+   .readable_reg = cs42l51_readable_reg,
+   .volatile_reg = cs42l51_volatile_reg,
+   .writeable_reg = cs42l51_writeable_reg,
.max_register = CS42L51_CHARGE_FREQ,
.cache_type = REGCACHE_RBTREE,
 };
@@ -597,6 +697,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
  

[PATCH 7/7] ASoC: cs42l51: add adc volume control

2019-04-03 Thread Olivier Moysan
Add ADC boost volume control for CS42L51 codec.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 25f17c0051e4..991e4ebd7a04 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -123,6 +123,7 @@ static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
 static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
 
 static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
+static const DECLARE_TLV_DB_SCALE(adc_boost_tlv, 2000, 2000, 0);
 static const char *chan_mix[] = {
"L R",
"L+R",
@@ -151,6 +152,8 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] 
= {
SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
SOC_DOUBLE_TLV("Mic Boost Volume",
CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
+   SOC_DOUBLE_TLV("ADC Boost Volume",
+  CS42L51_MIC_CTL, 5, 6, 1, 0, adc_boost_tlv),
SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
SOC_ENUM_EXT("PCM channel mixer",
-- 
2.7.4



[PATCH 1/7] ASoC: dt-bindings: update cs42l51 bindings

2019-04-03 Thread Olivier Moysan
Add compatible, reg, regulator, and reset
to Cirrus CS42L51 audio codec bindings.

Signed-off-by: Olivier Moysan 
---
 Documentation/devicetree/bindings/sound/cs42l51.txt | 16 
 1 file changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/cs42l51.txt 
b/Documentation/devicetree/bindings/sound/cs42l51.txt
index 4b5de33ce377..acbd68ddd2cb 100644
--- a/Documentation/devicetree/bindings/sound/cs42l51.txt
+++ b/Documentation/devicetree/bindings/sound/cs42l51.txt
@@ -1,6 +1,17 @@
 CS42L51 audio CODEC
 
+Required properties:
+
+  - compatible : "cirrus,cs42l51"
+
+  - reg : the I2C address of the device for I2C.
+
 Optional properties:
+  - VL-supply, VD-supply, VA-supply, VAHP-supply: power supplies for the 
device,
+as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
+
+  - reset-gpios : GPIO specification for the reset pin. If specified, it will 
be
+deasserted before starting the communication with the codec.
 
   - clocks : a list of phandles + clock-specifiers, one for each entry in
 clock-names
@@ -14,4 +25,9 @@ cs42l51: cs42l51@4a {
reg = <0x4a>;
clocks = <_prov>;
clock-names = "MCLK";
+   VL-supply = <_audio>;
+   VD-supply = <_audio>;
+   VA-supply = <_audio>;
+   VAHP-supply = <_audio>;
+   reset-gpios = < 9 GPIO_ACTIVE_LOW>;
 };
-- 
2.7.4



[PATCH 3/7] ASoC: cs42l51: add reset management

2019-04-03 Thread Olivier Moysan
Manage cs42l51 audio codec reset pin.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index f43eb51d2d8d..9b3ffa16b204 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -54,6 +55,7 @@ struct cs42l51_private {
unsigned int audio_mode;/* The mode (I2S or left-justified) */
enum master_slave_mode func;
struct regulator_bulk_data supplies[ARRAY_SIZE(cs42l51_supply_names)];
+   struct gpio_desc *reset_gpio;
 };
 
 #define CS42L51_FORMATS ( \
@@ -595,6 +597,17 @@ int cs42l51_probe(struct device *dev, struct regmap 
*regmap)
return ret;
}
 
+   cs42l51->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+   if (IS_ERR(cs42l51->reset_gpio))
+   return PTR_ERR(cs42l51->reset_gpio);
+
+   if (cs42l51->reset_gpio) {
+   dev_dbg(dev, "Release reset gpio\n");
+   gpiod_set_value_cansleep(cs42l51->reset_gpio, 0);
+   mdelay(2);
+   }
+
/* Verify that we have a CS42L51 */
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, );
if (ret < 0) {
@@ -629,6 +642,8 @@ int cs42l51_remove(struct device *dev)
 {
struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
 
+   gpiod_set_value_cansleep(cs42l51->reset_gpio, 1);
+
return regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
  cs42l51->supplies);
 }
-- 
2.7.4



[PATCH 4/7] ASoC: cs42l51: add support of master mode

2019-04-03 Thread Olivier Moysan
Add support of master mode for cs42l51 cirrus audio codec.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51.c | 30 +++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 9b3ffa16b204..397b68901d1c 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -340,6 +340,19 @@ static struct cs42l51_ratios slave_auto_ratios[] = {
{  256, CS42L51_DSM_MODE, 1 }, {  384, CS42L51_DSM_MODE, 1 },
 };
 
+/*
+ * Master mode mclk/fs ratios.
+ * Recommended configurations are SSM for 4-50khz and DSM for 50-100kHz ranges
+ * The table below provides support of following ratios:
+ * 128: SSM (%128) with div2 disabled
+ * 256: SSM (%128) with div2 enabled
+ * In both cases, if sampling rate is above 50kHz, SSM is overridden
+ * with DSM (%128) configuration
+ */
+static struct cs42l51_ratios master_ratios[] = {
+   { 128, CS42L51_SSM_MODE, 0 }, { 256, CS42L51_SSM_MODE, 1 },
+};
+
 static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
 {
@@ -362,11 +375,13 @@ static int cs42l51_hw_params(struct snd_pcm_substream 
*substream,
unsigned int ratio;
struct cs42l51_ratios *ratios = NULL;
int nr_ratios = 0;
-   int intf_ctl, power_ctl, fmt;
+   int intf_ctl, power_ctl, fmt, mode;
 
switch (cs42l51->func) {
case MODE_MASTER:
-   return -EINVAL;
+   ratios = master_ratios;
+   nr_ratios = ARRAY_SIZE(master_ratios);
+   break;
case MODE_SLAVE:
ratios = slave_ratios;
nr_ratios = ARRAY_SIZE(slave_ratios);
@@ -402,7 +417,16 @@ static int cs42l51_hw_params(struct snd_pcm_substream 
*substream,
switch (cs42l51->func) {
case MODE_MASTER:
intf_ctl |= CS42L51_INTF_CTL_MASTER;
-   power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+   mode = ratios[i].speed_mode;
+   /* Force DSM mode if sampling rate is above 50kHz */
+   if (rate > 5)
+   mode = CS42L51_DSM_MODE;
+   power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(mode);
+   /*
+* Auto detect mode is not applicable for master mode and has to
+* be disabled. Otherwise SPEED[1:0] bits will be ignored.
+*/
+   power_ctl &= ~CS42L51_MIC_POWER_CTL_AUTO;
break;
case MODE_SLAVE:
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
-- 
2.7.4



[PATCH 2/7] ASoC: cs42l51: add regulator management

2019-04-03 Thread Olivier Moysan
Add cs42l51 audio codec power supply management
through regulator framework.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51-i2c.c |  6 ++
 sound/soc/codecs/cs42l51.c | 44 +-
 sound/soc/codecs/cs42l51.h |  1 +
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index 4b5731a41876..8333dbf18ea2 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -35,12 +35,18 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c,
return cs42l51_probe(>dev, devm_regmap_init_i2c(i2c, ));
 }
 
+static int cs42l51_i2c_remove(struct i2c_client *i2c)
+{
+   return cs42l51_remove(>dev);
+}
+
 static struct i2c_driver cs42l51_i2c_driver = {
.driver = {
.name = "cs42l51",
.of_match_table = cs42l51_of_match,
},
.probe = cs42l51_i2c_probe,
+   .remove = cs42l51_i2c_remove,
.id_table = cs42l51_i2c_id,
 };
 
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 80da3cd73e04..f43eb51d2d8d 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "cs42l51.h"
 
@@ -40,11 +41,19 @@ enum master_slave_mode {
MODE_MASTER,
 };
 
+static const char * const cs42l51_supply_names[] = {
+   "VL",
+   "VD",
+   "VA",
+   "VAHP",
+};
+
 struct cs42l51_private {
unsigned int mclk;
struct clk *mclk_handle;
unsigned int audio_mode;/* The mode (I2S or left-justified) */
enum master_slave_mode func;
+   struct regulator_bulk_data supplies[ARRAY_SIZE(cs42l51_supply_names)];
 };
 
 #define CS42L51_FORMATS ( \
@@ -550,7 +559,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
 {
struct cs42l51_private *cs42l51;
unsigned int val;
-   int ret;
+   int ret, i;
 
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -569,6 +578,23 @@ int cs42l51_probe(struct device *dev, struct regmap 
*regmap)
cs42l51->mclk_handle = NULL;
}
 
+   for (i = 0; i < ARRAY_SIZE(cs42l51->supplies); i++)
+   cs42l51->supplies[i].supply = cs42l51_supply_names[i];
+
+   ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs42l51->supplies),
+ cs42l51->supplies);
+   if (ret != 0) {
+   dev_err(dev, "Failed to request supplies: %d\n", ret);
+   return ret;
+   }
+
+   ret = regulator_bulk_enable(ARRAY_SIZE(cs42l51->supplies),
+   cs42l51->supplies);
+   if (ret != 0) {
+   dev_err(dev, "Failed to enable supplies: %d\n", ret);
+   return ret;
+   }
+
/* Verify that we have a CS42L51 */
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, );
if (ret < 0) {
@@ -587,11 +613,27 @@ int cs42l51_probe(struct device *dev, struct regmap 
*regmap)
 
ret = devm_snd_soc_register_component(dev,
_component_device_cs42l51, _dai, 1);
+   if (ret < 0)
+   goto error;
+
+   return 0;
+
 error:
+   regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
+  cs42l51->supplies);
return ret;
 }
 EXPORT_SYMBOL_GPL(cs42l51_probe);
 
+int cs42l51_remove(struct device *dev)
+{
+   struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
+
+   return regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
+ cs42l51->supplies);
+}
+EXPORT_SYMBOL_GPL(cs42l51_remove);
+
 const struct of_device_id cs42l51_of_match[] = {
{ .compatible = "cirrus,cs42l51", },
{ }
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
index 0ca805492ac4..aef0ede82c7b 100644
--- a/sound/soc/codecs/cs42l51.h
+++ b/sound/soc/codecs/cs42l51.h
@@ -22,6 +22,7 @@ struct device;
 
 extern const struct regmap_config cs42l51_regmap;
 int cs42l51_probe(struct device *dev, struct regmap *regmap);
+int cs42l51_remove(struct device *dev);
 extern const struct of_device_id cs42l51_of_match[];
 
 #define CS42L51_CHIP_ID0x1B
-- 
2.7.4



[PATCH 0/7] ASoC: cs42l51: add some features

2019-04-03 Thread Olivier Moysan
This patchset add support of following features to Cirrus CS42L51 audio codec 
driver:
- reset
- regulators
- master mode
- power management
- adc volume control

Olivier Moysan (7):
  ASoC: dt-bindings: update cs42l51 bindings
  ASoC: cs42l51: add regulator management
  ASoC: cs42l51: add reset management
  ASoC: cs42l51: add support of master mode
  ASoC: cs42l51: change mic bias DAPM
  ASoC: cs42l51: add power management
  ASoC: cs42l51: add adc volume control

 .../devicetree/bindings/sound/cs42l51.txt  |  16 ++
 sound/soc/codecs/cs42l51-i2c.c |  13 +-
 sound/soc/codecs/cs42l51.c | 217 -
 sound/soc/codecs/cs42l51.h |   3 +
 4 files changed, 242 insertions(+), 7 deletions(-)

-- 
2.7.4



[PATCH] ASoC: cs42l51: add multi endpoint support

2019-03-29 Thread Olivier Moysan
Support multiple endpoints on cs42L51 codec port
when used in of_graph context.

This patch allows to share the codec port between two CPU DAIs.

Example:

STM32MP157C-DK2 board uses CS42L51 audio codec.
This codec is connected to two serial audio interfaces,
which are configured either as rx or tx.

>From AsoC point of view the topolgy is the following:
// 2 CPU DAIs (SAI2A/B), 1 Codec (CS42L51)
Playback: CPU-A-DAI(slave) -> (master)CODEC-DAI/port0
Record:   CPU-B-DAI(slave) <- (master)CODEC-DAI/port0

In the DT two endpoints have to be associated to the codec port:
cs42l51_port: port {
cs42l51_tx_endpoint: endpoint@0 {
remote-endpoint = <_endpoint>;
};
cs42l51_rx_endpoint: endpoint@1 {
remote-endpoint = <_endpoint>;
};
};

However, when the audio graph card parses the codec nodes, it expects
to find DAI interface indexes matching the endpoints indexes.

The current patch forces the use of DAI id 0 for both endpoints,
which allows to share the codec DAI between the two CPU DAIs
for playback and capture streams respectively.

Signed-off-by: Olivier Moysan 
---
 sound/soc/codecs/cs42l51.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index fd2bd74024c1..80da3cd73e04 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -464,6 +464,13 @@ static int cs42l51_dai_mute(struct snd_soc_dai *dai, int 
mute)
return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg);
 }
 
+static int cs42l51_of_xlate_dai_id(struct snd_soc_component *component,
+  struct device_node *endpoint)
+{
+   /* return dai id 0, whatever the endpoint index */
+   return 0;
+}
+
 static const struct snd_soc_dai_ops cs42l51_dai_ops = {
.hw_params  = cs42l51_hw_params,
.set_sysclk = cs42l51_set_dai_sysclk,
@@ -526,6 +533,7 @@ static const struct snd_soc_component_driver 
soc_component_device_cs42l51 = {
.num_dapm_widgets   = ARRAY_SIZE(cs42l51_dapm_widgets),
.dapm_routes= cs42l51_routes,
.num_dapm_routes= ARRAY_SIZE(cs42l51_routes),
+   .of_xlate_dai_id= cs42l51_of_xlate_dai_id,
.idle_bias_on   = 1,
.use_pmdown_time= 1,
.endianness = 1,
-- 
2.7.4



[PATCH 0/2] ARM: dts: stm32: add spdifrx support on stm32mp157c

2019-03-29 Thread Olivier Moysan
This patchset adds support of STM32 SPDFIRX on stm32mp157c

Olivier Moysan (2):
  ARM: dts: stm32: add spdifrx support on stm32mp157c
  ARM: dts: stm32: add spdfirx pins to stm32mp157c

 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 13 +
 arch/arm/boot/dts/stm32mp157c.dtsi| 13 +
 2 files changed, 26 insertions(+)

-- 
2.7.4



[PATCH 2/2] ARM: dts: stm32: add spdfirx pins to stm32mp157c

2019-03-29 Thread Olivier Moysan
This patch adds spdifrx support on stm32mp157c eval board.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 13 +
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi 
b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
index 9104896e6066..54c133094a8f 100644
--- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi
@@ -393,6 +393,19 @@
};
};
 
+   spdifrx_pins_a: spdifrx-0 {
+   pins {
+   pinmux = ; 
/* SPDIF_IN1 */
+   bias-disable;
+   };
+   };
+
+   spdifrx_sleep_pins_a: spdifrx-1 {
+   pins {
+   pinmux = ; /* SPDIF_IN1 */
+   };
+   };
+
uart4_pins_a: uart4-0 {
pins1 {
pinmux = ; 
/* UART4_TX */
-- 
2.7.4



[PATCH 1/2] ARM: dts: stm32: add spdifrx support on stm32mp157c

2019-03-29 Thread Olivier Moysan
This patch adds support of STM32 SPDIFRX on
stm32mp157c.

Signed-off-by: Olivier Moysan 
---
 arch/arm/boot/dts/stm32mp157c.dtsi | 13 +
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi 
b/arch/arm/boot/dts/stm32mp157c.dtsi
index 6ce75f696679..7769685d6361 100644
--- a/arch/arm/boot/dts/stm32mp157c.dtsi
+++ b/arch/arm/boot/dts/stm32mp157c.dtsi
@@ -580,6 +580,19 @@
status = "disabled";
};
 
+   spdifrx: audio-controller@4000d000 {
+   compatible = "st,stm32h7-spdifrx";
+   #sound-dai-cells = <0>;
+   reg = <0x4000d000 0x400>;
+   clocks = < SPDIF_K>;
+   clock-names = "kclk";
+   interrupts = ;
+   dmas = < 93 0x400 0x01>,
+  < 94 0x400 0x01>;
+   dma-names = "rx", "rx-ctrl";
+   status = "disabled";
+   };
+
spi1: spi@44004000 {
#address-cells = <1>;
#size-cells = <0>;
-- 
2.7.4



[PATCH] ASoC: stm32: sai: add power management

2019-03-21 Thread Olivier Moysan
Add support of low power modes to STM32 SAI driver.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai.c | 80 ++-
 sound/soc/stm/stm32_sai.h |  2 ++
 sound/soc/stm/stm32_sai_sub.c | 45 ++--
 3 files changed, 108 insertions(+), 19 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d68d62f12df5..7550d5f08be3 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -44,20 +45,41 @@ static const struct of_device_id stm32_sai_ids[] = {
{}
 };
 
-static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
+static int stm32_sai_pclk_disable(struct device *dev)
+{
+   struct stm32_sai_data *sai = dev_get_drvdata(dev);
+
+   clk_disable_unprepare(sai->pclk);
+
+   return 0;
+}
+
+static int stm32_sai_pclk_enable(struct device *dev)
 {
+   struct stm32_sai_data *sai = dev_get_drvdata(dev);
int ret;
 
-   /* Enable peripheral clock to allow GCR register access */
ret = clk_prepare_enable(sai->pclk);
if (ret) {
dev_err(>pdev->dev, "failed to enable clock: %d\n", ret);
return ret;
}
 
+   return 0;
+}
+
+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 = stm32_sai_pclk_enable(>pdev->dev);
+   if (ret)
+   return ret;
+
writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
 
-   clk_disable_unprepare(sai->pclk);
+   stm32_sai_pclk_disable(>pdev->dev);
 
return 0;
 }
@@ -68,11 +90,9 @@ static int stm32_sai_sync_conf_provider(struct 
stm32_sai_data *sai, int synco)
int ret;
 
/* Enable peripheral clock to allow GCR register access */
-   ret = clk_prepare_enable(sai->pclk);
-   if (ret) {
-   dev_err(>pdev->dev, "failed to enable clock: %d\n", ret);
+   ret = stm32_sai_pclk_enable(>pdev->dev);
+   if (ret)
return ret;
-   }
 
dev_dbg(>pdev->dev, "Set %pOFn%s as synchro provider\n",
sai->pdev->dev.of_node,
@@ -83,13 +103,13 @@ static int stm32_sai_sync_conf_provider(struct 
stm32_sai_data *sai, int synco)
dev_err(>pdev->dev, "%pOFn%s already set as sync 
provider\n",
sai->pdev->dev.of_node,
prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
-   clk_disable_unprepare(sai->pclk);
+   stm32_sai_pclk_disable(>pdev->dev);
return -EINVAL;
}
 
writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
 
-   clk_disable_unprepare(sai->pclk);
+   stm32_sai_pclk_disable(>pdev->dev);
 
return 0;
 }
@@ -195,12 +215,54 @@ static int stm32_sai_probe(struct platform_device *pdev)
return devm_of_platform_populate(>dev);
 }
 
+#ifdef CONFIG_PM_SLEEP
+/*
+ * When pins are shared by two sai sub instances, pins have to be defined
+ * in sai parent node. In this case, pins state is not managed by alsa fw.
+ * These pins are managed in suspend/resume callbacks.
+ */
+static int stm32_sai_suspend(struct device *dev)
+{
+   struct stm32_sai_data *sai = dev_get_drvdata(dev);
+   int ret;
+
+   ret = stm32_sai_pclk_enable(dev);
+   if (ret)
+   return ret;
+
+   sai->gcr = readl_relaxed(sai->base);
+   stm32_sai_pclk_disable(dev);
+
+   return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int stm32_sai_resume(struct device *dev)
+{
+   struct stm32_sai_data *sai = dev_get_drvdata(dev);
+   int ret;
+
+   ret = stm32_sai_pclk_enable(dev);
+   if (ret)
+   return ret;
+
+   writel_relaxed(sai->gcr, sai->base);
+   stm32_sai_pclk_disable(dev);
+
+   return pinctrl_pm_select_default_state(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops stm32_sai_pm_ops = {
+   SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume)
+};
+
 MODULE_DEVICE_TABLE(of, stm32_sai_ids);
 
 static struct platform_driver stm32_sai_driver = {
.driver = {
.name = "st,stm32-sai",
.of_match_table = stm32_sai_ids,
+   .pm = _sai_pm_ops,
},
.probe = stm32_sai_probe,
 };
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 08de899c766b..9c36a393ab7b 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -268,6 +268,7 @@ struct stm32_sai_conf {
  * @version: SOC version
  * @irq: SAI interrupt line
  * @set_sync: pointer to synchro mode c

[PATCH] ASoC: stm32: i2s: fix registers declaration in regmap

2019-03-11 Thread Olivier Moysan
- Declare SR as volatile, as it is changed by hardware.
- Remove TXDR from readable and volatile register list,
as it is intended for write accesses only.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index c18e068c1a0d..952634258b02 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -278,7 +278,6 @@ static bool stm32_i2s_readable_reg(struct device *dev, 
unsigned int reg)
case STM32_I2S_CFG2_REG:
case STM32_I2S_IER_REG:
case STM32_I2S_SR_REG:
-   case STM32_I2S_TXDR_REG:
case STM32_I2S_RXDR_REG:
case STM32_I2S_CGFR_REG:
return true;
@@ -290,7 +289,7 @@ static bool stm32_i2s_readable_reg(struct device *dev, 
unsigned int reg)
 static bool stm32_i2s_volatile_reg(struct device *dev, unsigned int reg)
 {
switch (reg) {
-   case STM32_I2S_TXDR_REG:
+   case STM32_I2S_SR_REG:
case STM32_I2S_RXDR_REG:
return true;
default:
-- 
2.7.4



[PATCH 3/3] ASoC: stm32: i2s: use default dai name

2019-03-11 Thread Olivier Moysan
Use default DAI name based on dev_name function.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 7 ---
 1 file changed, 7 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 06bbbef74b3a..c18e068c1a0d 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -179,7 +179,6 @@ enum i2s_datlen {
I2S_I2SMOD_DATLEN_32,
 };
 
-#define STM32_I2S_DAI_NAME_SIZE20
 #define STM32_I2S_FIFO_SIZE16
 
 #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER)
@@ -202,7 +201,6 @@ enum i2s_datlen {
  * @phys_addr: I2S registers physical base address
  * @lock_fd: lock to manage race conditions in full duplex mode
  * @irq_lock: prevent race condition with IRQ
- * @dais_name: DAI name
  * @mclk_rate: master clock frequency (Hz)
  * @fmt: DAI protocol
  * @refcount: keep count of opened streams on I2S
@@ -224,7 +222,6 @@ struct stm32_i2s_data {
dma_addr_t phys_addr;
spinlock_t lock_fd; /* Manage race conditions for full duplex */
spinlock_t irq_lock; /* used to prevent race condition with IRQ */
-   char dais_name[STM32_I2S_DAI_NAME_SIZE];
unsigned int mclk_rate;
unsigned int fmt;
int refcount;
@@ -771,12 +768,8 @@ static int stm32_i2s_dais_init(struct platform_device 
*pdev,
if (!dai_ptr)
return -ENOMEM;
 
-   snprintf(i2s->dais_name, STM32_I2S_DAI_NAME_SIZE,
-"%s", dev_name(>dev));
-
dai_ptr->probe = stm32_i2s_dai_probe;
dai_ptr->ops = _i2s_pcm_dai_ops;
-   dai_ptr->name = i2s->dais_name;
dai_ptr->id = 1;
stm32_i2s_dai_init(_ptr->playback, "playback");
stm32_i2s_dai_init(_ptr->capture, "capture");
-- 
2.7.4



[PATCH 0/3] ASoC: stm32: i2s: add minor improvements

2019-03-11 Thread Olivier Moysan
Add following minor changes in STM32 I2S driver:
- Change trigger traces
- Improve channel capabilities handling
- Use default dai name

Olivier Moysan (3):
  ASoC: stm32: i2s: change trigger traces
  ASoC: stm32: i2s: improve channel capabilities handling
  ASoC: stm32: i2s: use default dai name

 sound/soc/stm/stm32_i2s.c | 25 +
 1 file changed, 9 insertions(+), 16 deletions(-)

-- 
2.7.4



[PATCH 1/3] ASoC: stm32: i2s: change trigger traces

2019-03-11 Thread Olivier Moysan
Update traces to log capture/playback stream start/stop.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 47c334de6b09..783b33497435 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -593,7 +593,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream 
*substream, int cmd,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* Enable i2s */
-   dev_dbg(cpu_dai->dev, "start I2S\n");
+   dev_dbg(cpu_dai->dev, "start I2S %s\n",
+   playback_flg ? "playback" : "capture");
 
cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN;
regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG,
@@ -638,6 +639,9 @@ static int stm32_i2s_trigger(struct snd_pcm_substream 
*substream, int cmd,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+   dev_dbg(cpu_dai->dev, "stop I2S %s\n",
+   playback_flg ? "playback" : "capture");
+
if (playback_flg)
regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG,
   I2S_IER_UDRIE,
@@ -654,8 +658,6 @@ static int stm32_i2s_trigger(struct snd_pcm_substream 
*substream, int cmd,
break;
}
 
-   dev_dbg(cpu_dai->dev, "stop I2S\n");
-
ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG,
 I2S_CR1_SPE, 0);
if (ret < 0) {
-- 
2.7.4



[PATCH 2/3] ASoC: stm32: i2s: improve channel capabilities handling

2019-03-11 Thread Olivier Moysan
Use alsa snd_pcm_hw_constraint_single service to manage
channels restriction. This provides better status on driver
limitations, to the application.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 783b33497435..06bbbef74b3a 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -496,12 +496,6 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai,
unsigned int fthlv;
int ret;
 
-   if ((params_channels(params) == 1) &&
-   ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_DSP_A)) {
-   dev_err(cpu_dai->dev, "Mono mode supported only by DSP_A\n");
-   return -EINVAL;
-   }
-
switch (format) {
case 16:
cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16);
@@ -551,6 +545,10 @@ static int stm32_i2s_startup(struct snd_pcm_substream 
*substream,
i2s->substream = substream;
spin_unlock_irqrestore(>irq_lock, flags);
 
+   if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_DSP_A)
+   snd_pcm_hw_constraint_single(substream->runtime,
+SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+
ret = clk_prepare_enable(i2s->i2sclk);
if (ret < 0) {
dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret);
-- 
2.7.4



[PATCH] ASoC: stm32: spdifrx: add power management

2019-03-06 Thread Olivier Moysan
Add suspend and resume sleep callbacks to STM32 SPDIFRX driver,
to support system low power modes.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_spdifrx.c | 42 +++---
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 373df4f24be1..b4c3d983e195 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -471,6 +472,8 @@ static int stm32_spdifrx_get_ctrl_data(struct 
stm32_spdifrx_data *spdifrx)
memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB);
memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB);
 
+   pinctrl_pm_select_default_state(>pdev->dev);
+
ret = stm32_spdifrx_dma_ctrl_start(spdifrx);
if (ret < 0)
return ret;
@@ -502,6 +505,7 @@ static int stm32_spdifrx_get_ctrl_data(struct 
stm32_spdifrx_data *spdifrx)
 
 end:
clk_disable_unprepare(spdifrx->kclk);
+   pinctrl_pm_select_sleep_state(>pdev->dev);
 
return ret;
 }
@@ -611,10 +615,15 @@ static bool stm32_spdifrx_readable_reg(struct device 
*dev, unsigned int reg)
 
 static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg)
 {
-   if (reg == STM32_SPDIFRX_DR)
+   switch (reg) {
+   case STM32_SPDIFRX_DR:
+   case STM32_SPDIFRX_CSR:
+   case STM32_SPDIFRX_SR:
+   case STM32_SPDIFRX_DIR:
return true;
-
-   return false;
+   default:
+   return false;
+   }
 }
 
 static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg)
@@ -638,6 +647,7 @@ static const struct regmap_config 
stm32_h7_spdifrx_regmap_conf = {
.volatile_reg = stm32_spdifrx_volatile_reg,
.writeable_reg = stm32_spdifrx_writeable_reg,
.fast_io = true,
+   .cache_type = REGCACHE_FLAT,
 };
 
 static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
@@ -983,10 +993,36 @@ static int stm32_spdifrx_remove(struct platform_device 
*pdev)
 
 MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids);
 
+#ifdef CONFIG_PM_SLEEP
+static int stm32_spdifrx_suspend(struct device *dev)
+{
+   struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev);
+
+   regcache_cache_only(spdifrx->regmap, true);
+   regcache_mark_dirty(spdifrx->regmap);
+
+   return 0;
+}
+
+static int stm32_spdifrx_resume(struct device *dev)
+{
+   struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev);
+
+   regcache_cache_only(spdifrx->regmap, false);
+
+   return regcache_sync(spdifrx->regmap);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops stm32_spdifrx_pm_ops = {
+   SET_SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume)
+};
+
 static struct platform_driver stm32_spdifrx_driver = {
.driver = {
.name = "st,stm32-spdifrx",
.of_match_table = stm32_spdifrx_ids,
+   .pm = _spdifrx_pm_ops,
},
.probe = stm32_spdifrx_probe,
.remove = stm32_spdifrx_remove,
-- 
2.7.4



[PATCH 0/3] ASoC: stm32: dfsdm: fixes

2019-03-04 Thread Olivier Moysan
This patch-set provides the following fixes for STM32 DFSDM:
- manage multiple prepare
- fix debugfs warnings on entry creation
- add mmap support

Olivier Moysan (3):
  ASoC: stm32: dfsdm: manage multiple prepare
  ASoC: stm32: dfsdm: fix debugfs warnings on entry creation
  ASoC: stm32: dfsdm: add mmap support

 sound/soc/stm/stm32_adfsdm.c | 40 +++-
 1 file changed, 35 insertions(+), 5 deletions(-)

-- 
2.7.4



[PATCH 3/3] ASoC: stm32: dfsdm: add mmap support

2019-03-04 Thread Olivier Moysan
Enable direct access (mmap) support.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_adfsdm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 24948b95eb19..0d3040aef7f6 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -44,7 +44,7 @@ struct stm32_adfsdm_priv {
 
 static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-   SNDRV_PCM_INFO_PAUSE,
+   SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
 
.rate_min = 8000,
-- 
2.7.4



[PATCH 2/3] ASoC: stm32: dfsdm: fix debugfs warnings on entry creation

2019-03-04 Thread Olivier Moysan
Register platform component with a prefix, to avoid warnings
on debugfs entries creation, due to component name
redundancy.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_adfsdm.c | 21 ++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 71d341b732a4..24948b95eb19 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -304,6 +304,7 @@ MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match);
 static int stm32_adfsdm_probe(struct platform_device *pdev)
 {
struct stm32_adfsdm_priv *priv;
+   struct snd_soc_component *component;
int ret;
 
priv = devm_kzalloc(>dev, sizeof(*priv), GFP_KERNEL);
@@ -331,9 +332,15 @@ static int stm32_adfsdm_probe(struct platform_device *pdev)
if (IS_ERR(priv->iio_cb))
return PTR_ERR(priv->iio_cb);
 
-   ret = devm_snd_soc_register_component(>dev,
- _adfsdm_soc_platform,
- NULL, 0);
+   component = devm_kzalloc(>dev, sizeof(*component), GFP_KERNEL);
+   if (!component)
+   return -ENOMEM;
+#ifdef CONFIG_DEBUG_FS
+   component->debugfs_prefix = "pcm";
+#endif
+
+   ret = snd_soc_add_component(>dev, component,
+   _adfsdm_soc_platform, NULL, 0);
if (ret < 0)
dev_err(>dev, "%s: Failed to register PCM platform\n",
__func__);
@@ -341,12 +348,20 @@ static int stm32_adfsdm_probe(struct platform_device 
*pdev)
return ret;
 }
 
+static int stm32_adfsdm_remove(struct platform_device *pdev)
+{
+   snd_soc_unregister_component(>dev);
+
+   return 0;
+}
+
 static struct platform_driver stm32_adfsdm_driver = {
.driver = {
   .name = STM32_ADFSDM_DRV_NAME,
   .of_match_table = stm32_adfsdm_of_match,
   },
.probe = stm32_adfsdm_probe,
+   .remove = stm32_adfsdm_remove,
 };
 
 module_platform_driver(stm32_adfsdm_driver);
-- 
2.7.4



[PATCH 1/3] ASoC: stm32: dfsdm: manage multiple prepare

2019-03-04 Thread Olivier Moysan
The DFSDM must be stopped when a new setting is applied.
restart systematically DFSDM on multiple prepare calls,
to apply changes.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_adfsdm.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 706ff005234f..71d341b732a4 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -9,6 +9,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -37,6 +38,8 @@ struct stm32_adfsdm_priv {
/* PCM buffer */
unsigned char *pcm_buff;
unsigned int pos;
+
+   struct mutex lock; /* protect against race condition on iio state */
 };
 
 static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
@@ -62,10 +65,12 @@ static void stm32_adfsdm_shutdown(struct snd_pcm_substream 
*substream,
 {
struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
 
+   mutex_lock(>lock);
if (priv->iio_active) {
iio_channel_stop_all_cb(priv->iio_cb);
priv->iio_active = false;
}
+   mutex_unlock(>lock);
 }
 
 static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
@@ -74,13 +79,19 @@ static int stm32_adfsdm_dai_prepare(struct 
snd_pcm_substream *substream,
struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
int ret;
 
+   mutex_lock(>lock);
+   if (priv->iio_active) {
+   iio_channel_stop_all_cb(priv->iio_cb);
+   priv->iio_active = false;
+   }
+
ret = iio_write_channel_attribute(priv->iio_ch,
  substream->runtime->rate, 0,
  IIO_CHAN_INFO_SAMP_FREQ);
if (ret < 0) {
dev_err(dai->dev, "%s: Failed to set %d sampling rate\n",
__func__, substream->runtime->rate);
-   return ret;
+   goto out;
}
 
if (!priv->iio_active) {
@@ -92,6 +103,9 @@ static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream 
*substream,
__func__, ret);
}
 
+out:
+   mutex_unlock(>lock);
+
return ret;
 }
 
@@ -298,6 +312,7 @@ static int stm32_adfsdm_probe(struct platform_device *pdev)
 
priv->dev = >dev;
priv->dai_drv = stm32_adfsdm_dai;
+   mutex_init(>lock);
 
dev_set_drvdata(>dev, priv);
 
-- 
2.7.4



[PATCH 4/5] ASoC: stm32: sai: fix oversampling mode

2019-02-28 Thread Olivier Moysan
Set OSR bit if mclk/fs ratio is 512.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai_sub.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index cad415e03b5e..cb658463ccd1 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -913,7 +913,7 @@ static int stm32_sai_configure_clock(struct snd_soc_dai 
*cpu_dai,
 struct snd_pcm_hw_params *params)
 {
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
-   int div = 0;
+   int div = 0, cr1 = 0;
int sai_clk_rate, mclk_ratio, den;
unsigned int rate = params_rate(params);
 
@@ -958,13 +958,19 @@ static int stm32_sai_configure_clock(struct snd_soc_dai 
*cpu_dai,
} else {
if (sai->mclk_rate) {
mclk_ratio = sai->mclk_rate / rate;
-   if ((mclk_ratio != 512) &&
-   (mclk_ratio != 256)) {
+   if (mclk_ratio == 512) {
+   cr1 = SAI_XCR1_OSR;
+   } else if (mclk_ratio != 256) {
dev_err(cpu_dai->dev,
"Wrong mclk ratio %d\n",
mclk_ratio);
return -EINVAL;
}
+
+   regmap_update_bits(sai->regmap,
+  STM_SAI_CR1_REGX,
+  SAI_XCR1_OSR, cr1);
+
div = stm32_sai_get_clk_div(sai, sai_clk_rate,
sai->mclk_rate);
if (div < 0)
-- 
2.7.4



[PATCH 2/5] ASoC: stm32: sai: fix exposed capabilities in spdif mode

2019-02-28 Thread Olivier Moysan
Change capabilities exposed in SAI S/PDIF mode, to match
actually supported formats.
In S/PDIF mode only 32 bits stereo is supported.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai_sub.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 506360b7bc01..e418f446e03b 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -682,6 +682,14 @@ static int stm32_sai_startup(struct snd_pcm_substream 
*substream,
 
sai->substream = substream;
 
+   if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+   snd_pcm_hw_constraint_mask64(substream->runtime,
+SNDRV_PCM_HW_PARAM_FORMAT,
+SNDRV_PCM_FMTBIT_S32_LE);
+   snd_pcm_hw_constraint_single(substream->runtime,
+SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+   }
+
ret = clk_prepare_enable(sai->sai_ck);
if (ret < 0) {
dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret);
-- 
2.7.4



[PATCH 0/5] ASoC: stm32: sai: miscellaneous fixes

2019-02-28 Thread Olivier Moysan
This patch-set is a collection of fixes for STM32 SAI driver.

Olivier Moysan (5):
  ASoC: stm32: sai: fix iec958 controls indexation
  ASoC: stm32: sai: fix exposed capabilities in spdif mode
  ASoC: stm32: sai: fix race condition in irq handler
  ASoC: stm32: sai: fix oversampling mode
  ASoC: stm32: sai: fix set_sync service

 sound/soc/stm/stm32_sai.c |  7 ---
 sound/soc/stm/stm32_sai_sub.c | 48 ++-
 2 files changed, 42 insertions(+), 13 deletions(-)

-- 
2.7.4



[PATCH 5/5] ASoC: stm32: sai: fix set_sync service

2019-02-28 Thread Olivier Moysan
Add error check on set_sync function return.
Add of_node_put() as of_get_parent() takes a reference
which has to be released.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai.c | 8 +---
 sound/soc/stm/stm32_sai_sub.c | 8 +---
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index 14c9591aae42..d68d62f12df5 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -105,6 +105,7 @@ static int stm32_sai_set_sync(struct stm32_sai_data 
*sai_client,
if (!pdev) {
dev_err(_client->pdev->dev,
"Device not found for node %pOFn\n", np_provider);
+   of_node_put(np_provider);
return -ENODEV;
}
 
@@ -113,19 +114,20 @@ static int stm32_sai_set_sync(struct stm32_sai_data 
*sai_client,
dev_err(_client->pdev->dev,
"SAI sync provider data not found\n");
ret = -EINVAL;
-   goto out_put_dev;
+   goto error;
}
 
/* Configure sync client */
ret = stm32_sai_sync_conf_client(sai_client, synci);
if (ret < 0)
-   goto out_put_dev;
+   goto error;
 
/* Configure sync provider */
ret = stm32_sai_sync_conf_provider(sai_provider, synco);
 
-out_put_dev:
+error:
put_device(>dev);
+   of_node_put(np_provider);
return ret;
 }
 
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index cb658463ccd1..55d802f51c15 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -1106,7 +1106,7 @@ static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime 
*rtd,
 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;
+   int cr1 = 0, cr1_mask, ret;
 
sai->cpu_dai = cpu_dai;
 
@@ -1136,8 +1136,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai 
*cpu_dai)
/* 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);
+   ret = sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
+  sai->synco, sai->synci);
+   if (ret)
+   return ret;
}
 
cr1_mask |= SAI_XCR1_SYNCEN_MASK;
-- 
2.7.4



[PATCH 1/5] ASoC: stm32: sai: fix iec958 controls indexation

2019-02-28 Thread Olivier Moysan
Allow indexation of sai iec958 controls according
to device id.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai_sub.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index f9297228c41c..506360b7bc01 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -100,7 +100,7 @@
  * @slot_mask: rx or tx active slots mask. set at init or at runtime
  * @data_size: PCM data width. corresponds to PCM substream width.
  * @spdif_frm_cnt: S/PDIF playback frame counter
- * @snd_aes_iec958: iec958 data
+ * @iec958: iec958 data
  * @ctrl_lock: control lock
  */
 struct stm32_sai_sub_data {
@@ -1068,11 +1068,12 @@ static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime 
*rtd,
 struct snd_soc_dai *cpu_dai)
 {
struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+   struct snd_kcontrol_new knew = iec958_ctls;
 
if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
dev_dbg(>pdev->dev, "%s: register iec controls", __func__);
-   return snd_ctl_add(rtd->pcm->card,
-  snd_ctl_new1(_ctls, sai));
+   knew.device = rtd->pcm->device;
+   return snd_ctl_add(rtd->pcm->card, snd_ctl_new1(, sai));
}
 
return 0;
-- 
2.7.4



[PATCH 3/5] ASoC: stm32: sai: fix race condition in irq handler

2019-02-28 Thread Olivier Moysan
When snd_pcm_stop_xrun() is called in interrupt routine,
substream context may have already been released.
Add protection on substream context.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_sai_sub.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index e418f446e03b..cad415e03b5e 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -102,6 +102,7 @@
  * @spdif_frm_cnt: S/PDIF playback frame counter
  * @iec958: iec958 data
  * @ctrl_lock: control lock
+ * @irq_lock: prevent race condition with IRQ
  */
 struct stm32_sai_sub_data {
struct platform_device *pdev;
@@ -133,6 +134,7 @@ struct stm32_sai_sub_data {
unsigned int spdif_frm_cnt;
struct snd_aes_iec958 iec958;
struct mutex ctrl_lock; /* protect resources accessed by controls */
+   spinlock_t irq_lock; /* used to prevent race condition with IRQ */
 };
 
 enum stm32_sai_fifo_th {
@@ -474,8 +476,10 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
status = SNDRV_PCM_STATE_XRUN;
}
 
-   if (status != SNDRV_PCM_STATE_RUNNING)
+   spin_lock(>irq_lock);
+   if (status != SNDRV_PCM_STATE_RUNNING && sai->substream)
snd_pcm_stop_xrun(sai->substream);
+   spin_unlock(>irq_lock);
 
return IRQ_HANDLED;
 }
@@ -679,8 +683,11 @@ static int stm32_sai_startup(struct snd_pcm_substream 
*substream,
 {
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
int imr, cr2, ret;
+   unsigned long flags;
 
+   spin_lock_irqsave(>irq_lock, flags);
sai->substream = substream;
+   spin_unlock_irqrestore(>irq_lock, flags);
 
if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
snd_pcm_hw_constraint_mask64(substream->runtime,
@@ -1059,6 +1066,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream 
*substream,
   struct snd_soc_dai *cpu_dai)
 {
struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+   unsigned long flags;
 
regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
 
@@ -1069,7 +1077,9 @@ static void stm32_sai_shutdown(struct snd_pcm_substream 
*substream,
 
clk_rate_exclusive_put(sai->sai_mclk);
 
+   spin_lock_irqsave(>irq_lock, flags);
sai->substream = NULL;
+   spin_unlock_irqrestore(>irq_lock, flags);
 }
 
 static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd,
@@ -1433,6 +1443,7 @@ static int stm32_sai_sub_probe(struct platform_device 
*pdev)
 
sai->pdev = pdev;
mutex_init(>ctrl_lock);
+   spin_lock_init(>irq_lock);
platform_set_drvdata(pdev, sai);
 
sai->pdata = dev_get_drvdata(pdev->dev.parent);
-- 
2.7.4



[PATCH 2/7] ASoC: stm32: i2s: fix 16 bit format support

2019-02-26 Thread Olivier Moysan
I2S supports 16 bits data in 32 channel length.
However the expected driver behavior, is to
set channel length to 16 bits when data format is 16 bits.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 339cd4715b2e..7d4c67433916 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -501,7 +501,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai,
switch (format) {
case 16:
cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16);
-   cfgr_mask = I2S_CGFR_DATLEN_MASK;
+   cfgr_mask = I2S_CGFR_DATLEN_MASK | I2S_CGFR_CHLEN;
break;
case 32:
cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_32) |
-- 
2.7.4



[PATCH 7/7] ASoC: stm32: i2s: skip useless write in slave mode

2019-02-26 Thread Olivier Moysan
Dummy write in capture master mode is used to gate
bus clocks. This write is useless in slave mode
as the clocks are not managed by slave.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 42ce87a35104..47c334de6b09 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -623,8 +623,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream 
*substream, int cmd,
} else {
ier = I2S_IER_OVRIE;
 
-   if (i2s->refcount == 1)
-   /* dummy write to trigger capture */
+   if (STM32_I2S_IS_MASTER(i2s) && i2s->refcount == 1)
+   /* dummy write to gate bus clocks */
regmap_write(i2s->regmap,
 STM32_I2S_TXDR_REG, 0);
}
-- 
2.7.4



[PATCH 4/7] ASoC: stm32: i2s: fix dma configuration

2019-02-26 Thread Olivier Moysan
DMA configuration is not balanced on start/stop.
Move DMA configuration to trigger callback.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 7f56d7b51ba3..95fffb61faa5 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -488,7 +488,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai,
 {
struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai);
int format = params_width(params);
-   u32 cfgr, cfgr_mask, cfg1, cfg1_mask;
+   u32 cfgr, cfgr_mask, cfg1;
unsigned int fthlv;
int ret;
 
@@ -529,15 +529,11 @@ static int stm32_i2s_configure(struct snd_soc_dai 
*cpu_dai,
if (ret < 0)
return ret;
 
-   cfg1 = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN;
-   cfg1_mask = cfg1;
-
fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4;
-   cfg1 |= I2S_CFG1_FTHVL_SET(fthlv - 1);
-   cfg1_mask |= I2S_CFG1_FTHVL_MASK;
+   cfg1 = I2S_CFG1_FTHVL_SET(fthlv - 1);
 
return regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG,
- cfg1_mask, cfg1);
+ I2S_CFG1_FTHVL_MASK, cfg1);
 }
 
 static int stm32_i2s_startup(struct snd_pcm_substream *substream,
@@ -592,6 +588,10 @@ static int stm32_i2s_trigger(struct snd_pcm_substream 
*substream, int cmd,
/* Enable i2s */
dev_dbg(cpu_dai->dev, "start I2S\n");
 
+   cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN;
+   regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG,
+  cfg1_mask, cfg1_mask);
+
ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG,
 I2S_CR1_SPE, I2S_CR1_SPE);
if (ret < 0) {
-- 
2.7.4



[PATCH 5/7] ASoC: stm32: i2s: remove useless callback

2019-02-26 Thread Olivier Moysan
Clocks do not need to be released on driver removal,
as this is already managed before.
Remove useless remove callback.

Signed-off-by: Olivier Moysan 
---
 sound/soc/stm/stm32_i2s.c | 11 ---
 1 file changed, 11 deletions(-)

diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 95fffb61faa5..9edb753ffa1b 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -902,16 +902,6 @@ static int stm32_i2s_probe(struct platform_device *pdev)
  I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD);
 }
 
-static int stm32_i2s_remove(struct platform_device *pdev)
-{
-   struct stm32_i2s_data *i2s = platform_get_drvdata(pdev);
-
-   clk_disable_unprepare(i2s->i2sclk);
-   clk_disable_unprepare(i2s->pclk);
-
-   return 0;
-}
-
 MODULE_DEVICE_TABLE(of, stm32_i2s_ids);
 
 #ifdef CONFIG_PM_SLEEP
@@ -945,7 +935,6 @@ static struct platform_driver stm32_i2s_driver = {
.pm = _i2s_pm_ops,
},
.probe = stm32_i2s_probe,
-   .remove = stm32_i2s_remove,
 };
 
 module_platform_driver(stm32_i2s_driver);
-- 
2.7.4



  1   2   3   4   >