[PATCH v3 1/2] ASoC: stm32: add bindings for SAI
This patch adds documentation of device tree bindings for the STM32 SAI ASoC driver. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-sai.txt | 89 ++ 1 file changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt new file mode 100644 index 000..c59a3d7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -0,0 +1,89 @@ +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" + - reg: Base address and size of SAI common register set. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "x8k" and "x11k" + "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. + - clock-names: Must contain "sai_ck". + - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt + - 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/pinctrl-stm32.txt + +Example: +sound_card { + compatible = "audio-graph-card"; + dais = <_port>; +}; + +sai1: sai1@40015800 { + compatible = "st,stm32f4-sai"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + reg = <0x40015800 0x4>; + clocks = < 1 CLK_SAIQ_PDIV>, < 1 CLK_I2SQ_PDIV>; + clock-names = "x8k", "x11k"; + interrupts = <87>; + + sai1b: audio-controller@40015824 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-b"; + reg = <0x40015824 0x1C>; + clocks = < 1 CLK_SAI2>; + clock-names = "sai_ck"; + dmas = < 5 0 0x400 0x0>; + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <_sai1b>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + sai1b_port: port@0 { + reg = <0>; + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + audio-graph-card,format = "i2s"; + audio-graph-card,bitclock-master = <_endpoint>; + audio-graph-card,frame-master = <_endpoint>; + }; + }; + }; + }; +}; + +audio-codec { + codec_port: port { + codec_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; -- 1.9.1
[PATCH v3 2/2] ASoC: stm32: add SAI driver
This patch implements SAI ASoC driver for STM32. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/Kconfig | 1 + sound/soc/Makefile| 1 + sound/soc/stm/Kconfig | 8 + sound/soc/stm/Makefile| 6 + sound/soc/stm/stm32_sai.c | 115 ++ sound/soc/stm/stm32_sai.h | 200 ++ sound/soc/stm/stm32_sai_sub.c | 884 ++ 7 files changed, 1215 insertions(+) create mode 100644 sound/soc/stm/Kconfig create mode 100644 sound/soc/stm/Makefile create mode 100644 sound/soc/stm/stm32_sai.c create mode 100644 sound/soc/stm/stm32_sai.h create mode 100644 sound/soc/stm/stm32_sai_sub.c diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 182d92e..3836ebe 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -63,6 +63,7 @@ source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" source "sound/soc/spear/Kconfig" source "sound/soc/sti/Kconfig" +source "sound/soc/stm/Kconfig" source "sound/soc/sunxi/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 9a30f21..5440cf7 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ obj-$(CONFIG_SND_SOC) += spear/ obj-$(CONFIG_SND_SOC) += sti/ +obj-$(CONFIG_SND_SOC) += stm/ obj-$(CONFIG_SND_SOC) += sunxi/ obj-$(CONFIG_SND_SOC) += tegra/ obj-$(CONFIG_SND_SOC) += txx9/ diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig new file mode 100644 index 000..972970f --- /dev/null +++ b/sound/soc/stm/Kconfig @@ -0,0 +1,8 @@ +menuconfig SND_SOC_STM32 + tristate "STMicroelectronics STM32 SOC audio support" + depends on ARCH_STM32 || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y if you want to enable ASoC-support for STM32 diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile new file mode 100644 index 000..e466a47 --- /dev/null +++ b/sound/soc/stm/Makefile @@ -0,0 +1,6 @@ +# SAI +snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o + +snd-soc-stm32-sai-objs := stm32_sai.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c new file mode 100644 index 000..2a27a26 --- /dev/null +++ b/sound/soc/stm/stm32_sai.c @@ -0,0 +1,115 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (SAI) driver. + * + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan <olivier.moy...@st.com> for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "stm32_sai.h" + +static const struct of_device_id stm32_sai_ids[] = { + { .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 }, + {} +}; + +static int stm32_sai_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct stm32_sai_data *sai; + struct reset_control *rst; + struct resource *res; + void __iomem *base; + const struct of_device_id *of_id; + + sai = devm_kzalloc(>dev, sizeof(*sai), GFP_KERNEL); + if (!sai) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(>dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + of_id = of_match_device(stm32_sai_ids, >dev); + if (of_id) + sai->version = (enum stm32_sai_version)of_id->data; + else + return -EINVAL; + + sai->clk_x8k = devm_clk_get(>dev, "x8k"); + if (IS_ERR(sai->clk_x8k)) { + dev_err(>dev, "missing x8k parent clock\n"); + return PTR_ERR(sai->clk_x8k); + } + + sai->clk_x11k = devm_clk_get(>dev, "x11k"); + if (IS_ERR(sai->clk_x11k)) { + dev_err(>dev, "missing x11k parent clock\n"); + return PTR_ERR(sai->clk_x11k); + } + + /* init irqs */ + sai->irq = platform_get_irq(pdev, 0); + if (sai->irq < 0) { + dev_er
[PATCH v3 0/2] Add STM32 SAI support
This patch-set handles the Serial Audio Interface (SAI) IP on STM32 platforms. The SAI IP is composed of two Sub-block A and B. (see the figure below) Each sub-block makes use of individual and shared resources. Shared resources: - Reset line. Reset common and sub-block registers. - Bus interface clocks. This clock is not exposed in device as it it managed by clock driver, according to kernel clocks gating. - Common register. SAI IP exhibits a common configuration register to manage synchronization modes. NB: These modes are not yet implemented in this version of the SAI driver. - Interrupt. Sub-blocks have their own interrupt status registers but they share the same interrupt line. Individual resources: - Register set - DMA request line. - Communication interface. Each sub-block has its own GPIOs and associated bus lines. - Kernel clock. Each sub-block has its own dedicated clock for its communication interface. To reflect this architecture Sub-block A and B are handled by 2 child devices. Sub-block A and B devices can be configured independently either as transmitter or receiver. A PCM device is associated to each sub-block. A sub-block has to select the appropriated parent clock at runtime, depending on the audio stream sampling rate to be played or captured. Two parent clocks must be provided to support sampling rates multiples of 8 kHz or 11.025kHz. Interface clock ++ +---> | SAI IP | Reset| +-+| +---> | |common registers || | +-+| || |+--+| || Sub-block A || Kernel clock A || || Bus A +> | ++ +> || |A registers | || || ++ || |+--+| || |+--+| || Sub-block B || Kernel clock B || || Bus B +> | ++ +-> || |B registers | || || ++ || |+--+| || ++ v3: correct DT bindings - remove aliases - use audio graph card olivier moysan (2): ASoC: stm32: add bindings for SAI ASoC: stm32: add SAI driver .../devicetree/bindings/sound/st,stm32-sai.txt | 89 +++ sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/stm/Kconfig | 8 + sound/soc/stm/Makefile | 6 + sound/soc/stm/stm32_sai.c | 115 +++ sound/soc/stm/stm32_sai.h | 200 + sound/soc/stm/stm32_sai_sub.c | 884 + 8 files changed, 1304 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt create mode 100644 sound/soc/stm/Kconfig create mode 100644 sound/soc/stm/Makefile create mode 100644 sound/soc/stm/stm32_sai.c create mode 100644 sound/soc/stm/stm32_sai.h create mode 100644 sound/soc/stm/stm32_sai_sub.c -- 1.9.1
[PATCH v4 2/2] ASoC: stm32: add SAI driver
This patch implements SAI ASoC driver for STM32. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/Kconfig | 1 + sound/soc/Makefile| 1 + sound/soc/stm/Kconfig | 8 + sound/soc/stm/Makefile| 6 + sound/soc/stm/stm32_sai.c | 115 ++ sound/soc/stm/stm32_sai.h | 199 ++ sound/soc/stm/stm32_sai_sub.c | 881 ++ 7 files changed, 1211 insertions(+) create mode 100644 sound/soc/stm/Kconfig create mode 100644 sound/soc/stm/Makefile create mode 100644 sound/soc/stm/stm32_sai.c create mode 100644 sound/soc/stm/stm32_sai.h create mode 100644 sound/soc/stm/stm32_sai_sub.c diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 9df9658..c0abad2 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -64,6 +64,7 @@ source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" source "sound/soc/spear/Kconfig" source "sound/soc/sti/Kconfig" +source "sound/soc/stm/Kconfig" source "sound/soc/sunxi/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 2f6aabb..39c27a5 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ obj-$(CONFIG_SND_SOC) += spear/ obj-$(CONFIG_SND_SOC) += sti/ +obj-$(CONFIG_SND_SOC) += stm/ obj-$(CONFIG_SND_SOC) += sunxi/ obj-$(CONFIG_SND_SOC) += tegra/ obj-$(CONFIG_SND_SOC) += txx9/ diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig new file mode 100644 index 000..a6372de --- /dev/null +++ b/sound/soc/stm/Kconfig @@ -0,0 +1,8 @@ +menuconfig SND_SOC_STM32 + tristate "STMicroelectronics STM32 SOC audio support" + depends on ARCH_STM32 || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y if you want to enable ASoC support for STM32 diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile new file mode 100644 index 000..e466a47 --- /dev/null +++ b/sound/soc/stm/Makefile @@ -0,0 +1,6 @@ +# SAI +snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o + +snd-soc-stm32-sai-objs := stm32_sai.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c new file mode 100644 index 000..6159d66 --- /dev/null +++ b/sound/soc/stm/stm32_sai.c @@ -0,0 +1,115 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (SAI) driver. + * + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan <olivier.moy...@st.com> for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "stm32_sai.h" + +static const struct of_device_id stm32_sai_ids[] = { + { .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 }, + {} +}; + +static int stm32_sai_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct stm32_sai_data *sai; + struct reset_control *rst; + struct resource *res; + void __iomem *base; + const struct of_device_id *of_id; + + sai = devm_kzalloc(>dev, sizeof(*sai), GFP_KERNEL); + if (!sai) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(>dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + of_id = of_match_device(stm32_sai_ids, >dev); + if (of_id) + sai->version = (enum stm32_sai_version)of_id->data; + else + return -EINVAL; + + sai->clk_x8k = devm_clk_get(>dev, "x8k"); + if (IS_ERR(sai->clk_x8k)) { + dev_err(>dev, "missing x8k parent clock\n"); + return PTR_ERR(sai->clk_x8k); + } + + sai->clk_x11k = devm_clk_get(>dev, "x11k"); + if (IS_ERR(sai->clk_x11k)) { + dev_err(>dev, "missing x11k parent clock\n"); + return PTR_ERR(sai->clk_x11k); + } + + /* init irqs */ + sai->irq = platform_get_irq(pdev, 0); + if (sai->irq < 0) { + dev_er
[PATCH v4 1/2] ASoC: stm32: add bindings for SAI
This patch adds documentation of device tree bindings for the STM32 SAI ASoC driver. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-sai.txt | 89 ++ 1 file changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt new file mode 100644 index 000..c59a3d7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -0,0 +1,89 @@ +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" + - reg: Base address and size of SAI common register set. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "x8k" and "x11k" + "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. + - clock-names: Must contain "sai_ck". + - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt + - 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/pinctrl-stm32.txt + +Example: +sound_card { + compatible = "audio-graph-card"; + dais = <_port>; +}; + +sai1: sai1@40015800 { + compatible = "st,stm32f4-sai"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + reg = <0x40015800 0x4>; + clocks = < 1 CLK_SAIQ_PDIV>, < 1 CLK_I2SQ_PDIV>; + clock-names = "x8k", "x11k"; + interrupts = <87>; + + sai1b: audio-controller@40015824 { + #sound-dai-cells = <0>; + compatible = "st,stm32-sai-sub-b"; + reg = <0x40015824 0x1C>; + clocks = < 1 CLK_SAI2>; + clock-names = "sai_ck"; + dmas = < 5 0 0x400 0x0>; + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <_sai1b>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + sai1b_port: port@0 { + reg = <0>; + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + audio-graph-card,format = "i2s"; + audio-graph-card,bitclock-master = <_endpoint>; + audio-graph-card,frame-master = <_endpoint>; + }; + }; + }; + }; +}; + +audio-codec { + codec_port: port { + codec_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; -- 1.9.1
[PATCH v4 0/2] Add STM32 SAI support
This patch-set handles the Serial Audio Interface (SAI) IP on STM32 platforms. The SAI IP is composed of two Sub-block A and B. (see the figure below) Each sub-block makes use of individual and shared resources. Shared resources: - Reset line. Reset common and sub-block registers. - Bus interface clocks. This clock is not exposed in device as it it managed by clock driver, according to kernel clocks gating. - Common register. SAI IP exhibits a common configuration register to manage synchronization modes. NB: These modes are not yet implemented in this version of the SAI driver. - Interrupt. Sub-blocks have their own interrupt status registers but they share the same interrupt line. Individual resources: - Register set - DMA request line. - Communication interface. Each sub-block has its own GPIOs and associated bus lines. - Kernel clock. Each sub-block has its own dedicated clock for its communication interface. To reflect this architecture Sub-block A and B are handled by 2 child devices. Sub-block A and B devices can be configured independently either as transmitter or receiver. A PCM device is associated to each sub-block. A sub-block has to select the appropriated parent clock at runtime, depending on the audio stream sampling rate to be played or captured. Two parent clocks must be provided to support sampling rates multiples of 8 kHz or 11.025kHz. Interface clock ++ +---> | SAI IP | Reset| +-+| +---> | |common registers || | +-+| || |+--+| || Sub-block A || Kernel clock A || || Bus A +> | ++ +> || |A registers | || || ++ || |+--+| || |+--+| || Sub-block B || Kernel clock B || || Bus B +> | ++ +-> || |B registers | || || ++ || |+--+| || ++ v3 -> v4 Apply minor changes from Peter review olivier moysan (2): ASoC: stm32: add bindings for SAI ASoC: stm32: add SAI driver .../devicetree/bindings/sound/st,stm32-sai.txt | 89 +++ sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/stm/Kconfig | 8 + sound/soc/stm/Makefile | 6 + sound/soc/stm/stm32_sai.c | 115 +++ sound/soc/stm/stm32_sai.h | 199 + sound/soc/stm/stm32_sai_sub.c | 881 + 8 files changed, 1300 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt create mode 100644 sound/soc/stm/Kconfig create mode 100644 sound/soc/stm/Makefile create mode 100644 sound/soc/stm/stm32_sai.c create mode 100644 sound/soc/stm/stm32_sai.h create mode 100644 sound/soc/stm/stm32_sai_sub.c -- 1.9.1
[PATCH v3 2/3] ASoC: stm32: Add I2S driver
Add I2S ASoC driver for STM32. This version of the driver supports only exclusive playback and capture interface. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 2 +- sound/soc/stm/Makefile| 4 + sound/soc/stm/stm32_i2s.c | 941 ++ 3 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 sound/soc/stm/stm32_i2s.c diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 972970f..a6372de 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -5,4 +5,4 @@ menuconfig SND_SOC_STM32 select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help - Say Y if you want to enable ASoC-support for STM32 + Say Y if you want to enable ASoC support for STM32 diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index e466a47..8251931 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o + +# I2S +snd-soc-stm32-i2s-objs := stm32_i2s.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-i2s.o diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c new file mode 100644 index 000..22152a1 --- /dev/null +++ b/sound/soc/stm/stm32_i2s.c @@ -0,0 +1,941 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (I2S) driver. + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan <olivier.moy...@st.com> for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STM32_I2S_CR1_REG 0x0 +#define STM32_I2S_CFG1_REG 0x08 +#define STM32_I2S_CFG2_REG 0x0C +#define STM32_I2S_IER_REG 0x10 +#define STM32_I2S_SR_REG 0x14 +#define STM32_I2S_IFCR_REG 0x18 +#define STM32_I2S_TXDR_REG 0X20 +#define STM32_I2S_RXDR_REG 0x30 +#define STM32_I2S_CGFR_REG 0X50 + +/* Bit definition for SPI2S_CR1 register */ +#define I2S_CR1_SPEBIT(0) +#define I2S_CR1_CSTART BIT(9) +#define I2S_CR1_CSUSP BIT(10) +#define I2S_CR1_HDDIR BIT(11) +#define I2S_CR1_SSIBIT(12) +#define I2S_CR1_CRC33_17 BIT(13) +#define I2S_CR1_RCRCI BIT(14) +#define I2S_CR1_TCRCI BIT(15) + +/* Bit definition for SPI_CFG2 register */ +#define I2S_CFG2_IOSWP_SHIFT 15 +#define I2S_CFG2_IOSWP BIT(I2S_CFG2_IOSWP_SHIFT) +#define I2S_CFG2_LSBFRST BIT(23) +#define I2S_CFG2_AFCNTRBIT(31) + +/* Bit definition for SPI_CFG1 register */ +#define I2S_CFG1_FTHVL_SHIFT 5 +#define I2S_CFG1_FTHVL_MASKGENMASK(8, I2S_CFG1_FTHVL_SHIFT) +#define I2S_CFG1_FTHVL_SET(x) ((x) << I2S_CFG1_FTHVL_SHIFT) + +#define I2S_CFG1_TXDMAEN BIT(15) +#define I2S_CFG1_RXDMAEN BIT(14) + +/* Bit definition for SPI2S_IER register */ +#define I2S_IER_RXPIE BIT(0) +#define I2S_IER_TXPIE BIT(1) +#define I2S_IER_DPXPIE BIT(2) +#define I2S_IER_EOTIE BIT(3) +#define I2S_IER_TXTFIE BIT(4) +#define I2S_IER_UDRIE BIT(5) +#define I2S_IER_OVRIE BIT(6) +#define I2S_IER_CRCEIE BIT(7) +#define I2S_IER_TIFREIEBIT(8) +#define I2S_IER_MODFIE BIT(9) +#define I2S_IER_TSERFIEBIT(10) + +/* Bit definition for SPI2S_SR register */ +#define I2S_SR_RXP BIT(0) +#define I2S_SR_TXP BIT(1) +#define I2S_SR_DPXPBIT(2) +#define I2S_SR_EOT BIT(3) +#define I2S_SR_TXTFBIT(4) +#define I2S_SR_UDR BIT(5) +#define I2S_SR_OVR BIT(6) +#define I2S_SR_CRCERR BIT(7) +#define I2S_SR_TIFRE BIT(8) +#define I2S_SR_MODFBIT(9) +#define I2S_SR_TSERF BIT(10) +#define I2S_SR_SUSPBIT(11) +#define I2S_SR_TXC BIT(12) +#define I2S_SR_RXPLVL GENMASK(14, 13) +#define I2S_SR_RXWNE BIT(15) + +#define I2S_SR_MASKGENMASK(15, 0) + +/* Bit definition for SPI_IFCR register */ +#define I2S_IFCR_EOTC BIT(3) +#define I2S_IFCR_TXTFC BIT(4) +#define I2S_IFCR_UDRC BIT(5) +#define I2S_IFCR_OVRC BIT(6) +#define I2S_IFCR_CRCEC BIT(7) +#define I2S_IFCR_TIFRECBIT(8) +#define I2S_IFCR_MODFC BIT(9) +#define I2S_IFCR_TSERFC
[PATCH v3 0/3] Add I2S driver
This patch-set handles the SPI/I2S IP on STM32 platforms. It applies to STM32 platforms implementing version 2 of SPI/I2S IP like STM32H7 series. The SPI/I2S block is a serial peripheral interface (SPI), which can also be configured to work on I2S/PCM mode. ASoC STM32 I2S driver only supports this I2S/PCM mode. The I2S/PCM interface can either support full duplex or half-duplex communication (transmitter or receiver only). The change of mode requires to stop the interface. This means that the two audio paths cannot be basically managed independently. The driver supports playback and capture through a single bidirectionnal DAI. In the first version of the driver, playback and capture paths are made mutually exclusive. A second patch introduces support of full duplex mode. In this implementation the interface is systematically configured in full-duplex mode from hardware point of view. So, when managing a single audio path, the interface is not configured as transmit or receive only, as it should be. This restriction is handled by masking underrun/overrun errors from the unused path. The I2S/PCM interface supports four audio standards: I2S Philips standard, MSB justified standard, LSB justified standard, PCM standard PCM standard is declined in two versions, PCM short and long, according frame synchronization duration. These standards can be mapped to ASoC standards as follows: - I2S: i2s - MSB justified standard: left_j - LSB justified standard: right_j - PCM short: dsp_a PCM long format is not exposed as it does not match supported ASoC standards. v2 -> v3 - fix spinlock handling olivier moysan (3): dt-bindings: Document STM32 I2S bindings ASoC: stm32: Add I2S driver ASoC: stm32: Add full duplex support to i2s .../devicetree/bindings/sound/st,stm32-i2s.txt | 68 ++ sound/soc/stm/Kconfig | 2 +- sound/soc/stm/Makefile | 4 + sound/soc/stm/stm32_i2s.c | 946 + 4 files changed, 1019 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt create mode 100644 sound/soc/stm/stm32_i2s.c -- 1.9.1
[PATCH v3 3/3] ASoC: stm32: Add full duplex support to i2s
This patch allows to use i2s interface either as single audio path (rx or tx), or bidirectional audio path. This patch is added separately, as the driver does not follow recommended use of the interface, to support this configuration. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_i2s.c | 87 +-- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 22152a1..8052629 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -489,7 +489,6 @@ 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; - bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); unsigned int fthlv; int ret; @@ -515,19 +514,13 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, } if (STM32_I2S_IS_SLAVE(i2s)) { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_SLAVE); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_SLAVE); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_SLAVE); /* As data length is either 16 or 32 bits, fixch always set */ cfgr |= I2S_CGFR_FIXCH; cfgr_mask |= I2S_CGFR_FIXCH; } else { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_MASTER); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_MASTER); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_MASTER); } cfgr_mask |= I2S_CGFR_I2SCFG_MASK; @@ -536,9 +529,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, if (ret < 0) return ret; - cfg1 = I2S_CFG1_RXDMAEN; - if (playback_flg) - cfg1 = I2S_CFG1_TXDMAEN; + cfg1 = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; cfg1_mask = cfg1; fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4; @@ -553,32 +544,15 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); - int ret, ier; i2s->substream = substream; spin_lock(>lock_fd); - if (i2s->refcount) { - dev_err(cpu_dai->dev, "%s stream already started\n", - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "Capture" : "Playback")); - spin_unlock(>lock_fd); - return -EBUSY; - } - i2s->refcount = 1; + i2s->refcount++; spin_unlock(>lock_fd); - ret = regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, -I2S_IFCR_MASK, I2S_IFCR_MASK); - if (ret < 0) - return ret; - - /* Enable ITs */ - ier = I2S_IER_OVRIE | I2S_IER_UDRIE; - if (STM32_I2S_IS_SLAVE(i2s)) - ier |= I2S_IER_TIFREIE; - - return regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, ier, ier); + return regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); } static int stm32_i2s_hw_params(struct snd_pcm_substream *substream, @@ -605,7 +579,7 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - u32 cfg1_mask; + u32 cfg1_mask, ier; int ret; switch (cmd) { @@ -628,10 +602,48 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); return ret; } + + regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); + + if (playback_flg) { + ier = I2S_IER_UDRIE; + } else { + ier = I2S_IER_OVRIE; + + spin_lock(>lock_fd); + if (i2s->refcount == 1) + /* dummy write to trigger capture */ + regmap_write(i2s->regmap, +STM32_I2S_TXDR_REG, 0); + spin_unlock(>lock_fd); + } + + if (STM32_I2S_IS_SLAVE(i2s)) + ier |= I2S_IER_TIFREIE; + +
[PATCH v3 1/3] dt-bindings: Document STM32 I2S bindings
Add documentation of device tree bindings for STM32 SPI/I2S. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-i2s.txt | 68 ++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt new file mode 100644 index 000..67b854a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt @@ -0,0 +1,68 @@ +STMicroelectronics STM32 SPI/I2S Controller + +The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. +Only some SPI instances support I2S. + +Required properties: + - compatible: Must be "st,stm32h7-i2s" + - reg: Offset and length of the device's register set. + - interrupts: Must contain the interrupt line id. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k". + "i2sclk": clock which feeds the internal clock generator + "pclk": clock which feeds the peripheral bus interface + "x8k": I2S parent clock for sampling rates multiple of 8kHz. + "x11k": I2S parent clock for sampling rates multiple of 11.025kHz. + - dmas: DMA specifiers for tx and rx dma. +See Documentation/devicetree/bindings/dma/stm32-dma.txt. + - dma-names: Identifier for each DMA request line. Must be "tx" and "rx". + - pinctrl-names: should contain only value "default" + - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt + +Optional properties: + - resets: Reference to a reset controller asserting the reset controller + +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 0>; +}; + +i2s2: audio-controller@40003800 { + compatible = "st,stm32h7-i2s"; + #sound-dai-cells = <0>; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = < PCLK1>, < SPI2_CK>, < PLL1_Q>, < PLL2_P>; + clock-names = "pclk", "i2sclk", "x8k", "x11k"; + dmas = < 2 39 0x400 0x1>, + < 3 40 0x400 0x1>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <_i2s2>; + + i2s2_port: port@0 { + #address-cells = <1>; + #size-cells = <0>; + + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + format = "i2s"; + bitclock-master = <_endpoint>; + frame-master = <_endpoint>; + }; + }; +}; + +audio-codec { + codec_port: port@0 { + codec_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; -- 1.9.1
[PATCH v2 0/3] Add I2S driver
This patch-set handles the SPI/I2S IP on STM32 platforms. It applies to STM32 platforms implementing version 2 of SPI/I2S IP like STM32H7 series. The SPI/I2S block is a serial peripheral interface (SPI), which can also be configured to work on I2S/PCM mode. ASoC STM32 I2S driver only supports this I2S/PCM mode. The I2S/PCM interface can either support full duplex or half-duplex communication (transmitter or receiver only). The change of mode requires to stop the interface. This means that the two audio paths cannot be basically managed independently. The driver supports playback and capture through a single bidirectionnal DAI. In the first version of the driver, playback and capture paths are made mutually exclusive. A second patch introduces support of full duplex mode. In this implementation the interface is systematically configured in full-duplex mode from hardware point of view. So, when managing a single audio path, the interface is not configured as transmit or receive only, as it should be. This restriction is handled by masking underrun/overrun errors from the unused path. The I2S/PCM interface supports four audio standards: I2S Philips standard, MSB justified standard, LSB justified standard, PCM standard PCM standard is declined in two versions, PCM short and long, according frame synchronization duration. These standards can be mapped to ASoC standards as follows: - I2S: i2s - MSB justified standard: left_j - LSB justified standard: right_j - PCM short: dsp_a PCM long format is not exposed as it does not match supported ASoC standards. olivier moysan (3): dt-bindings: Document STM32 I2S bindings ASoC: stm32: Add I2S driver ASoC: stm32: Add full duplex support to i2s .../devicetree/bindings/sound/st,stm32-i2s.txt | 68 ++ sound/soc/stm/Kconfig | 2 +- sound/soc/stm/Makefile | 4 + sound/soc/stm/stm32_i2s.c | 947 + 4 files changed, 1020 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt create mode 100644 sound/soc/stm/stm32_i2s.c -- 1.9.1
[PATCH v2 3/3] ASoC: stm32: Add full duplex support to i2s
This patch allows to use i2s interface either as single audio path (rx or tx), or bidirectional audio path. This patch is added separately, as the driver does not follow recommended use of the interface, to support this configuration. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_i2s.c | 88 +-- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 22152a1..a8e03c5 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -489,7 +489,6 @@ 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; - bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); unsigned int fthlv; int ret; @@ -515,19 +514,13 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, } if (STM32_I2S_IS_SLAVE(i2s)) { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_SLAVE); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_SLAVE); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_SLAVE); /* As data length is either 16 or 32 bits, fixch always set */ cfgr |= I2S_CGFR_FIXCH; cfgr_mask |= I2S_CGFR_FIXCH; } else { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_MASTER); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_MASTER); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_MASTER); } cfgr_mask |= I2S_CGFR_I2SCFG_MASK; @@ -536,9 +529,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, if (ret < 0) return ret; - cfg1 = I2S_CFG1_RXDMAEN; - if (playback_flg) - cfg1 = I2S_CFG1_TXDMAEN; + cfg1 = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; cfg1_mask = cfg1; fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4; @@ -553,32 +544,15 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); - int ret, ier; i2s->substream = substream; spin_lock(>lock_fd); - if (i2s->refcount) { - dev_err(cpu_dai->dev, "%s stream already started\n", - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "Capture" : "Playback")); - spin_unlock(>lock_fd); - return -EBUSY; - } - i2s->refcount = 1; + i2s->refcount++; spin_unlock(>lock_fd); - ret = regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, -I2S_IFCR_MASK, I2S_IFCR_MASK); - if (ret < 0) - return ret; - - /* Enable ITs */ - ier = I2S_IER_OVRIE | I2S_IER_UDRIE; - if (STM32_I2S_IS_SLAVE(i2s)) - ier |= I2S_IER_TIFREIE; - - return regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, ier, ier); + return regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); } static int stm32_i2s_hw_params(struct snd_pcm_substream *substream, @@ -605,9 +579,11 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - u32 cfg1_mask; + u32 cfg1_mask, ier; int ret; + spin_lock(>lock_fd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -628,10 +604,45 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); return ret; } + + regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); + + if (playback_flg) { + ier = I2S_IER_UDRIE; + } else { + ier = I2S_IER_OVRIE; + + if (i2s->refcount == 1) { + /* dummy write to trigger capture */ + ret = regmap_write(i2s->regmap, + STM32_I2S_TXDR_REG, 0); + if (ret) + return ret; +
[PATCH v2 2/3] ASoC: stm32: Add I2S driver
Add I2S ASoC driver for STM32. This version of the driver supports only exclusive playback and capture interface. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 2 +- sound/soc/stm/Makefile| 4 + sound/soc/stm/stm32_i2s.c | 941 ++ 3 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 sound/soc/stm/stm32_i2s.c diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 972970f..a6372de 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -5,4 +5,4 @@ menuconfig SND_SOC_STM32 select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help - Say Y if you want to enable ASoC-support for STM32 + Say Y if you want to enable ASoC support for STM32 diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index e466a47..8251931 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o + +# I2S +snd-soc-stm32-i2s-objs := stm32_i2s.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-i2s.o diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c new file mode 100644 index 000..22152a1 --- /dev/null +++ b/sound/soc/stm/stm32_i2s.c @@ -0,0 +1,941 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (I2S) driver. + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan <olivier.moy...@st.com> for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STM32_I2S_CR1_REG 0x0 +#define STM32_I2S_CFG1_REG 0x08 +#define STM32_I2S_CFG2_REG 0x0C +#define STM32_I2S_IER_REG 0x10 +#define STM32_I2S_SR_REG 0x14 +#define STM32_I2S_IFCR_REG 0x18 +#define STM32_I2S_TXDR_REG 0X20 +#define STM32_I2S_RXDR_REG 0x30 +#define STM32_I2S_CGFR_REG 0X50 + +/* Bit definition for SPI2S_CR1 register */ +#define I2S_CR1_SPEBIT(0) +#define I2S_CR1_CSTART BIT(9) +#define I2S_CR1_CSUSP BIT(10) +#define I2S_CR1_HDDIR BIT(11) +#define I2S_CR1_SSIBIT(12) +#define I2S_CR1_CRC33_17 BIT(13) +#define I2S_CR1_RCRCI BIT(14) +#define I2S_CR1_TCRCI BIT(15) + +/* Bit definition for SPI_CFG2 register */ +#define I2S_CFG2_IOSWP_SHIFT 15 +#define I2S_CFG2_IOSWP BIT(I2S_CFG2_IOSWP_SHIFT) +#define I2S_CFG2_LSBFRST BIT(23) +#define I2S_CFG2_AFCNTRBIT(31) + +/* Bit definition for SPI_CFG1 register */ +#define I2S_CFG1_FTHVL_SHIFT 5 +#define I2S_CFG1_FTHVL_MASKGENMASK(8, I2S_CFG1_FTHVL_SHIFT) +#define I2S_CFG1_FTHVL_SET(x) ((x) << I2S_CFG1_FTHVL_SHIFT) + +#define I2S_CFG1_TXDMAEN BIT(15) +#define I2S_CFG1_RXDMAEN BIT(14) + +/* Bit definition for SPI2S_IER register */ +#define I2S_IER_RXPIE BIT(0) +#define I2S_IER_TXPIE BIT(1) +#define I2S_IER_DPXPIE BIT(2) +#define I2S_IER_EOTIE BIT(3) +#define I2S_IER_TXTFIE BIT(4) +#define I2S_IER_UDRIE BIT(5) +#define I2S_IER_OVRIE BIT(6) +#define I2S_IER_CRCEIE BIT(7) +#define I2S_IER_TIFREIEBIT(8) +#define I2S_IER_MODFIE BIT(9) +#define I2S_IER_TSERFIEBIT(10) + +/* Bit definition for SPI2S_SR register */ +#define I2S_SR_RXP BIT(0) +#define I2S_SR_TXP BIT(1) +#define I2S_SR_DPXPBIT(2) +#define I2S_SR_EOT BIT(3) +#define I2S_SR_TXTFBIT(4) +#define I2S_SR_UDR BIT(5) +#define I2S_SR_OVR BIT(6) +#define I2S_SR_CRCERR BIT(7) +#define I2S_SR_TIFRE BIT(8) +#define I2S_SR_MODFBIT(9) +#define I2S_SR_TSERF BIT(10) +#define I2S_SR_SUSPBIT(11) +#define I2S_SR_TXC BIT(12) +#define I2S_SR_RXPLVL GENMASK(14, 13) +#define I2S_SR_RXWNE BIT(15) + +#define I2S_SR_MASKGENMASK(15, 0) + +/* Bit definition for SPI_IFCR register */ +#define I2S_IFCR_EOTC BIT(3) +#define I2S_IFCR_TXTFC BIT(4) +#define I2S_IFCR_UDRC BIT(5) +#define I2S_IFCR_OVRC BIT(6) +#define I2S_IFCR_CRCEC BIT(7) +#define I2S_IFCR_TIFRECBIT(8) +#define I2S_IFCR_MODFC BIT(9) +#define I2S_IFCR_TSERFC
[PATCH v2 1/3] dt-bindings: Document STM32 I2S bindings
Add documentation of device tree bindings for STM32 SPI/I2S. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-i2s.txt | 68 ++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt new file mode 100644 index 000..67b854a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt @@ -0,0 +1,68 @@ +STMicroelectronics STM32 SPI/I2S Controller + +The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. +Only some SPI instances support I2S. + +Required properties: + - compatible: Must be "st,stm32h7-i2s" + - reg: Offset and length of the device's register set. + - interrupts: Must contain the interrupt line id. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k". + "i2sclk": clock which feeds the internal clock generator + "pclk": clock which feeds the peripheral bus interface + "x8k": I2S parent clock for sampling rates multiple of 8kHz. + "x11k": I2S parent clock for sampling rates multiple of 11.025kHz. + - dmas: DMA specifiers for tx and rx dma. +See Documentation/devicetree/bindings/dma/stm32-dma.txt. + - dma-names: Identifier for each DMA request line. Must be "tx" and "rx". + - pinctrl-names: should contain only value "default" + - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt + +Optional properties: + - resets: Reference to a reset controller asserting the reset controller + +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 0>; +}; + +i2s2: audio-controller@40003800 { + compatible = "st,stm32h7-i2s"; + #sound-dai-cells = <0>; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = < PCLK1>, < SPI2_CK>, < PLL1_Q>, < PLL2_P>; + clock-names = "pclk", "i2sclk", "x8k", "x11k"; + dmas = < 2 39 0x400 0x1>, + < 3 40 0x400 0x1>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <_i2s2>; + + i2s2_port: port@0 { + #address-cells = <1>; + #size-cells = <0>; + + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + format = "i2s"; + bitclock-master = <_endpoint>; + frame-master = <_endpoint>; + }; + }; +}; + +audio-codec { + codec_port: port@0 { + codec_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; -- 1.9.1
[PATCH v2 2/2] ASoC: stm32: Add SPDIFRX support
Add SPDIFRX support to STM32. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 10 + sound/soc/stm/Makefile| 4 + sound/soc/stm/stm32_spdifrx.c | 998 ++ 3 files changed, 1012 insertions(+) create mode 100644 sound/soc/stm/stm32_spdifrx.c diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 23600a5..3398e6c 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -18,4 +18,14 @@ config SND_SOC_STM32_I2S help Say Y if you want to enable I2S for STM32 +config SND_SOC_STM32_SPDIFRX + tristate "STM32 S/PDIF receiver (SPDIFRX) support" + depends on ARCH_STM32 || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + select SND_SOC_SPDIF + help + Say Y if you want to enable S/PDIF capture for STM32 + endmenu diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index 4140c67..4ed22e6 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -8,3 +8,7 @@ obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o # I2S snd-soc-stm32-i2s-objs := stm32_i2s.o obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o + +# SPDIFRX +snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o +obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c new file mode 100644 index 000..4e4250b --- /dev/null +++ b/sound/soc/stm/stm32_spdifrx.c @@ -0,0 +1,998 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver. + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan <olivier.moy...@st.com> for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* SPDIF-rx Register Map */ +#define STM32_SPDIFRX_CR 0x00 +#define STM32_SPDIFRX_IMR 0x04 +#define STM32_SPDIFRX_SR 0x08 +#define STM32_SPDIFRX_IFCR 0x0C +#define STM32_SPDIFRX_DR 0x10 +#define STM32_SPDIFRX_CSR 0x14 +#define STM32_SPDIFRX_DIR 0x18 + +/* Bit definition for SPDIF_CR register */ +#define SPDIFRX_CR_SPDIFEN_SHIFT 0 +#define SPDIFRX_CR_SPDIFEN_MASKGENMASK(1, SPDIFRX_CR_SPDIFEN_SHIFT) +#define SPDIFRX_CR_SPDIFENSET(x) ((x) << SPDIFRX_CR_SPDIFEN_SHIFT) + +#define SPDIFRX_CR_RXDMAEN BIT(2) +#define SPDIFRX_CR_RXSTEO BIT(3) + +#define SPDIFRX_CR_DRFMT_SHIFT 4 +#define SPDIFRX_CR_DRFMT_MASK GENMASK(5, SPDIFRX_CR_DRFMT_SHIFT) +#define SPDIFRX_CR_DRFMTSET(x) ((x) << SPDIFRX_CR_DRFMT_SHIFT) + +#define SPDIFRX_CR_PMSKBIT(6) +#define SPDIFRX_CR_VMSKBIT(7) +#define SPDIFRX_CR_CUMSK BIT(8) +#define SPDIFRX_CR_PTMSK BIT(9) +#define SPDIFRX_CR_CBDMAEN BIT(10) +#define SPDIFRX_CR_CHSEL_SHIFT 11 +#define SPDIFRX_CR_CHSEL BIT(SPDIFRX_CR_CHSEL_SHIFT) + +#define SPDIFRX_CR_NBTR_SHIFT 12 +#define SPDIFRX_CR_NBTR_MASK GENMASK(13, SPDIFRX_CR_NBTR_SHIFT) +#define SPDIFRX_CR_NBTRSET(x) ((x) << SPDIFRX_CR_NBTR_SHIFT) + +#define SPDIFRX_CR_WFA BIT(14) + +#define SPDIFRX_CR_INSEL_SHIFT 16 +#define SPDIFRX_CR_INSEL_MASK GENMASK(18, PDIFRX_CR_INSEL_SHIFT) +#define SPDIFRX_CR_INSELSET(x) ((x) << SPDIFRX_CR_INSEL_SHIFT) + +#define SPDIFRX_CR_CKSEN_SHIFT 20 +#define SPDIFRX_CR_CKSEN BIT(20) +#define SPDIFRX_CR_CKSBKPENBIT(21) + +/* Bit definition for SPDIFRX_IMR register */ +#define SPDIFRX_IMR_RXNEI BIT(0) +#define SPDIFRX_IMR_CSRNEIEBIT(1) +#define SPDIFRX_IMR_PERRIE BIT(2) +#define SPDIFRX_IMR_OVRIE BIT(3) +#define SPDIFRX_IMR_SBLKIE BIT(4) +#define SPDIFRX_IMR_SYNCDIEBIT(5) +#define SPDIFRX_IMR_IFEIE BIT(6) + +#define SPDIFRX_XIMR_MASK GENMASK(6, 0) + +/* Bit definition for SPDIFRX_SR register */ +#define SPDIFRX_SR_RXNEBIT(0) +#define SPDIFRX_SR_CSRNE BIT(1) +#define SPDIFRX_SR_PERRBIT(2) +#define SPDIFRX_SR_OVR BIT(3) +#define SPDIFRX_SR_SBD BIT(4) +#define SPDIFRX_SR_SYNCD BIT(5) +#define SPDIFRX_SR_FERRBIT(6) +#define SPDIFRX_SR_SERRBIT(7) +#define SPDIFRX_SR_TERRBIT(8) + +#define SPDIFRX_SR_WIDTH5_SHIFT16 +#define SPDIFRX_SR_WIDTH5_MASK GENMASK(30, PDIFRX_SR_WIDTH5_SHIFT) +#define SPDIFRX_SR_WIDTH5SET(x)((x) << SPDIFRX_SR_WIDTH5_S
[PATCH v2 1/2] ASoC: stm32: Add DT bindings for SPDIFRX interface
Add documentation of device tree bindings for the STM32 SPDIFRX interface. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-spdifrx.txt | 56 ++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt new file mode 100644 index 000..33826f2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt @@ -0,0 +1,56 @@ +STMicroelectronics STM32 S/PDIF receiver (SPDIFRX). + +The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with +IEC-60958 and IEC-61937. + +Required properties: + - compatible: should be "st,stm32h7-spdifrx" + - reg: cpu DAI IP base address and size + - clocks: must contain an entry for kclk (used as S/PDIF signal reference) + - clock-names: must contain "kclk" + - interrupts: cpu DAI interrupt line + - dmas: DMA specifiers for audio data DMA and iec control flow DMA +See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt + - dma-names: two dmas have to be defined, "rx" and "rx-ctrl" + +Optional properties: + - resets: Reference to a reset controller asserting the SPDIFRX + +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: +spdifrx: spdifrx@40004000 { + compatible = "st,stm32h7-spdifrx"; + reg = <0x40004000 0x400>; + clocks = < SPDIFRX_CK>; + clock-names = "kclk"; + interrupts = <97>; + dmas = < 2 93 0x400 0x0>, + < 3 94 0x400 0x0>; + dma-names = "rx", "rx-ctrl"; + pinctrl-0 = <_pins>; + pinctrl-names = "default"; + + spdifrx_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; + +spdif_in: spdif-in { + compatible = "linux,spdif-dir"; + + codec_port: port { + codec_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; + +soundcard { + compatible = "audio-graph-card"; + dais = <_port>; +}; -- 1.9.1
[PATCH v2 0/2] ASoC: stm32: add SPDIFRX driver
This patch-set handles the SPDIFRX on STM32 platforms. The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with IEC-60958 and IEC-61937 standards. SPDIFRX uses two DMA channels: - one DMA channel for S/PDIF data stream. - one DMA channel for control flow (channel status and user data bits). DMA is used for control flow instead of interrupts to get better performances, as channel status and user data are retrieved byte per byte. v1 -> v2: - fix merge issue olivier moysan (2): ASoC: stm32: Add DT bindings for SPDIFRX interface ASoC: stm32: Add SPDIFRX support .../devicetree/bindings/sound/st,stm32-spdifrx.txt | 56 ++ sound/soc/stm/Kconfig | 10 + sound/soc/stm/Makefile | 4 + sound/soc/stm/stm32_spdifrx.c | 998 + 4 files changed, 1068 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt create mode 100644 sound/soc/stm/stm32_spdifrx.c -- 1.9.1
Re: [PATCH 1/2] dt-bindings: Document the STM32 SPDIFRX interface
Hello Rob, On 06/23/2017 08:55 PM, Rob Herring wrote: > On Fri, Jun 16, 2017 at 03:57:31PM +0200, olivier moysan wrote: >> This adds documentation of device tree bindings for the >> STM32 SPDIFRX interface. >> >> Signed-off-by: olivier moysan <olivier.moy...@st.com> >> --- >> .../devicetree/bindings/sound/st,stm32-spdifrx.txt | 56 >> ++ >> 1 file changed, 56 insertions(+) >> create mode 100644 >> Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt >> >> diff --git a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt >> b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt >> new file mode 100644 >> index 000..33826f2 >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt >> @@ -0,0 +1,56 @@ >> +STMicroelectronics STM32 S/PDIF receiver (SPDIFRX). >> + >> +The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with >> +IEC-60958 and IEC-61937. >> + >> +Required properties: >> + - compatible: should be "st,stm32h7-spdifrx" >> + - reg: cpu DAI IP base address and size >> + - clocks: must contain an entry for kclk (used as S/PDIF signal reference) >> + - clock-names: must contain "kclk" >> + - interrupts: cpu DAI interrupt line >> + - dmas: DMA specifiers for audio data DMA and iec control flow DMA >> +See STM32 DMA bindings, >> Documentation/devicetree/bindings/dma/stm32-dma.txt >> + - dma-names: two dmas have to be defined, "rx" and "rx-ctrl" >> + >> +Optional properties: >> + - resets: Reference to a reset controller asserting the SPDIFRX >> + >> +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: >> +spdifrx: spdifrx@40004000 { >> +compatible = "st,stm32h7-spdifrx"; >> +reg = <0x40004000 0x400>; >> +clocks = < SPDIFRX_CK>; >> +clock-names = "kclk"; >> +interrupts = <97>; >> +dmas = < 2 93 0x400 0x0>, >> + < 3 94 0x400 0x0>; >> +dma-names = "rx", "rx-ctrl"; >> +pinctrl-0 = <_pins>; >> +pinctrl-names = "default"; >> + >> +spdifrx_port: port { >> +cpu_endpoint: endpoint { >> +remote-endpoint = <_endpoint>; >> +}; >> +}; >> +}; >> + >> +spdif_in: spdif-in { >> +compatible = "linux,spdif-dir"; > > What is this? It should go. > > Rob > This is the ASoC spdif stub codec. This is relevant in DT when spdif interface is wired to a connector. I will remove it from bindings. BRs olivier
Re: [PATCH v3 1/3] dt-bindings: Document STM32 I2S bindings
Hello Rob, Thanks for your comment. On 05/13/2017 02:17 AM, Rob Herring wrote: > On Thu, May 11, 2017 at 11:45:02AM +0200, olivier moysan wrote: >> Add documentation of device tree bindings for STM32 SPI/I2S. >> >> Signed-off-by: olivier moysan <olivier.moy...@st.com> >> --- >> .../devicetree/bindings/sound/st,stm32-i2s.txt | 68 >> ++ >> 1 file changed, 68 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt >> >> diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt >> b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt >> new file mode 100644 >> index 000..67b854a >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt >> @@ -0,0 +1,68 @@ >> +STMicroelectronics STM32 SPI/I2S Controller >> + >> +The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. >> +Only some SPI instances support I2S. >> + >> +Required properties: >> + - compatible: Must be "st,stm32h7-i2s" >> + - reg: Offset and length of the device's register set. >> + - interrupts: Must contain the interrupt line id. >> + - clocks: Must contain phandle and clock specifier pairs for each entry >> +in clock-names. >> + - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k". >> +"i2sclk": clock which feeds the internal clock generator >> +"pclk": clock which feeds the peripheral bus interface >> +"x8k": I2S parent clock for sampling rates multiple of 8kHz. >> +"x11k": I2S parent clock for sampling rates multiple of 11.025kHz. >> + - dmas: DMA specifiers for tx and rx dma. >> +See Documentation/devicetree/bindings/dma/stm32-dma.txt. >> + - dma-names: Identifier for each DMA request line. Must be "tx" and "rx". >> + - pinctrl-names: should contain only value "default" >> + - pinctrl-0: see >> Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt >> + >> +Optional properties: >> + - resets: Reference to a reset controller asserting the reset controller >> + >> +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 0>; > > What is the 0 representing? > This is no more relevant, so to be removed. >> +}; >> + >> +i2s2: audio-controller@40003800 { >> +compatible = "st,stm32h7-i2s"; >> +#sound-dai-cells = <0>; > > Should be dropped. > ok >> +reg = <0x40003800 0x400>; >> +interrupts = <36>; >> +clocks = < PCLK1>, < SPI2_CK>, < PLL1_Q>, < PLL2_P>; >> +clock-names = "pclk", "i2sclk", "x8k", "x11k"; >> +dmas = < 2 39 0x400 0x1>, >> + < 3 40 0x400 0x1>; >> +dma-names = "rx", "tx"; >> +pinctrl-names = "default"; >> +pinctrl-0 = <_i2s2>; >> + >> +i2s2_port: port@0 { >> +#address-cells = <1>; >> +#size-cells = <0>; > > This shouldn't even compile. You don't need these because because you > have no reg property in the endpoint. > > You have a unit-address here w/o a reg property. You don't need a reg > prop because you only have 1 port. > ok. >> + >> +cpu_endpoint: endpoint { >> +remote-endpoint = <_endpoint>; >> +format = "i2s"; >> +bitclock-master = <_endpoint>; >> +frame-master = <_endpoint>; >> +}; >> +}; >> +}; >> + >> +audio-codec { >> +codec_port: port@0 { >> +codec_endpoint: endpoint { >> +remote-endpoint = <_endpoint>; >> +}; >> +}; >> +}; >> -- >> 1.9.1 >> BRs Olivier
[PATCH v4 3/3] ASoC: stm32: Add full duplex support to i2s
This patch allows to use i2s interface either as single audio path (rx or tx), or bidirectional audio path. This patch is added separately, as the driver does not follow recommended use of the interface, to support this configuration. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_i2s.c | 87 +-- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 22152a1..8052629 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -489,7 +489,6 @@ 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; - bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); unsigned int fthlv; int ret; @@ -515,19 +514,13 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, } if (STM32_I2S_IS_SLAVE(i2s)) { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_SLAVE); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_SLAVE); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_SLAVE); /* As data length is either 16 or 32 bits, fixch always set */ cfgr |= I2S_CGFR_FIXCH; cfgr_mask |= I2S_CGFR_FIXCH; } else { - if (playback_flg) - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_TX_MASTER); - else - cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_RX_MASTER); + cfgr |= I2S_CGFR_I2SCFG_SET(I2S_I2SMOD_FD_MASTER); } cfgr_mask |= I2S_CGFR_I2SCFG_MASK; @@ -536,9 +529,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, if (ret < 0) return ret; - cfg1 = I2S_CFG1_RXDMAEN; - if (playback_flg) - cfg1 = I2S_CFG1_TXDMAEN; + cfg1 = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; cfg1_mask = cfg1; fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4; @@ -553,32 +544,15 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); - int ret, ier; i2s->substream = substream; spin_lock(>lock_fd); - if (i2s->refcount) { - dev_err(cpu_dai->dev, "%s stream already started\n", - (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "Capture" : "Playback")); - spin_unlock(>lock_fd); - return -EBUSY; - } - i2s->refcount = 1; + i2s->refcount++; spin_unlock(>lock_fd); - ret = regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, -I2S_IFCR_MASK, I2S_IFCR_MASK); - if (ret < 0) - return ret; - - /* Enable ITs */ - ier = I2S_IER_OVRIE | I2S_IER_UDRIE; - if (STM32_I2S_IS_SLAVE(i2s)) - ier |= I2S_IER_TIFREIE; - - return regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, ier, ier); + return regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); } static int stm32_i2s_hw_params(struct snd_pcm_substream *substream, @@ -605,7 +579,7 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); bool playback_flg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); - u32 cfg1_mask; + u32 cfg1_mask, ier; int ret; switch (cmd) { @@ -628,10 +602,48 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); return ret; } + + regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); + + if (playback_flg) { + ier = I2S_IER_UDRIE; + } else { + ier = I2S_IER_OVRIE; + + spin_lock(>lock_fd); + if (i2s->refcount == 1) + /* dummy write to trigger capture */ + regmap_write(i2s->regmap, +STM32_I2S_TXDR_REG, 0); + spin_unlock(>lock_fd); + } + + if (STM32_I2S_IS_SLAVE(i2s)) + ier |= I2S_IER_TIFREIE; + +
[PATCH v4 0/3] ASoC: Add STM32 I2S support
This patch-set handles the SPI/I2S IP on STM32 platforms. It applies to STM32 platforms implementing version 2 of SPI/I2S IP like STM32H7 series. The SPI/I2S block is a serial peripheral interface (SPI), which can also be configured to work on I2S/PCM mode. ASoC STM32 I2S driver only supports this I2S/PCM mode. The I2S/PCM interface can either support full duplex or half-duplex communication (transmitter or receiver only). The change of mode requires to stop the interface. This means that the two audio paths cannot be basically managed independently. The driver supports playback and capture through a single bidirectionnal DAI. In the first version of the driver, playback and capture paths are made mutually exclusive. A second patch introduces support of full duplex mode. In this implementation the interface is systematically configured in full-duplex mode from hardware point of view. So, when managing a single audio path, the interface is not configured as transmit or receive only, as it should be. This restriction is handled by masking underrun/overrun errors from the unused path. The I2S/PCM interface supports four audio standards: I2S Philips standard, MSB justified standard, LSB justified standard, PCM standard PCM standard is declined in two versions, PCM short and long, according frame synchronization duration. These standards can be mapped to ASoC standards as follows: - I2S: i2s - MSB justified standard: left_j - LSB justified standard: right_j - PCM short: dsp_a PCM long format is not exposed as it does not match supported ASoC standards. v3 -> v4 - update example in dt bindings olivier moysan (3): dt-bindings: Document STM32 I2S bindings ASoC: stm32: Add I2S driver ASoC: stm32: Add full duplex support to i2s .../devicetree/bindings/sound/st,stm32-i2s.txt | 62 ++ sound/soc/stm/Kconfig | 2 +- sound/soc/stm/Makefile | 4 + sound/soc/stm/stm32_i2s.c | 946 + 4 files changed, 1013 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt create mode 100644 sound/soc/stm/stm32_i2s.c -- 1.9.1
[PATCH v4 1/3] dt-bindings: Document STM32 I2S bindings
Add documentation of device tree bindings for STM32 SPI/I2S. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-i2s.txt | 62 ++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt new file mode 100644 index 000..4bda520 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt @@ -0,0 +1,62 @@ +STMicroelectronics STM32 SPI/I2S Controller + +The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. +Only some SPI instances support I2S. + +Required properties: + - compatible: Must be "st,stm32h7-i2s" + - reg: Offset and length of the device's register set. + - interrupts: Must contain the interrupt line id. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k". + "i2sclk": clock which feeds the internal clock generator + "pclk": clock which feeds the peripheral bus interface + "x8k": I2S parent clock for sampling rates multiple of 8kHz. + "x11k": I2S parent clock for sampling rates multiple of 11.025kHz. + - dmas: DMA specifiers for tx and rx dma. +See Documentation/devicetree/bindings/dma/stm32-dma.txt. + - dma-names: Identifier for each DMA request line. Must be "tx" and "rx". + - pinctrl-names: should contain only value "default" + - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt + +Optional properties: + - resets: Reference to a reset controller asserting the reset controller + +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>; +}; + +i2s2: audio-controller@40003800 { + compatible = "st,stm32h7-i2s"; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = < PCLK1>, < SPI2_CK>, < PLL1_Q>, < PLL2_P>; + clock-names = "pclk", "i2sclk", "x8k", "x11k"; + dmas = < 2 39 0x400 0x1>, + < 3 40 0x400 0x1>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <_i2s2>; + + i2s2_port: port@0 { + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + format = "i2s"; + }; + }; +}; + +audio-codec { + codec_port: port@0 { + codec_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; -- 1.9.1
[PATCH v4 2/3] ASoC: stm32: Add I2S driver
Add I2S ASoC driver for STM32. This version of the driver supports only exclusive playback and capture interface. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 2 +- sound/soc/stm/Makefile| 4 + sound/soc/stm/stm32_i2s.c | 941 ++ 3 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 sound/soc/stm/stm32_i2s.c diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 972970f..a6372de 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -5,4 +5,4 @@ menuconfig SND_SOC_STM32 select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help - Say Y if you want to enable ASoC-support for STM32 + Say Y if you want to enable ASoC support for STM32 diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index e466a47..8251931 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o + +# I2S +snd-soc-stm32-i2s-objs := stm32_i2s.o +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-i2s.o diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c new file mode 100644 index 000..22152a1 --- /dev/null +++ b/sound/soc/stm/stm32_i2s.c @@ -0,0 +1,941 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (I2S) driver. + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan <olivier.moy...@st.com> for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define STM32_I2S_CR1_REG 0x0 +#define STM32_I2S_CFG1_REG 0x08 +#define STM32_I2S_CFG2_REG 0x0C +#define STM32_I2S_IER_REG 0x10 +#define STM32_I2S_SR_REG 0x14 +#define STM32_I2S_IFCR_REG 0x18 +#define STM32_I2S_TXDR_REG 0X20 +#define STM32_I2S_RXDR_REG 0x30 +#define STM32_I2S_CGFR_REG 0X50 + +/* Bit definition for SPI2S_CR1 register */ +#define I2S_CR1_SPEBIT(0) +#define I2S_CR1_CSTART BIT(9) +#define I2S_CR1_CSUSP BIT(10) +#define I2S_CR1_HDDIR BIT(11) +#define I2S_CR1_SSIBIT(12) +#define I2S_CR1_CRC33_17 BIT(13) +#define I2S_CR1_RCRCI BIT(14) +#define I2S_CR1_TCRCI BIT(15) + +/* Bit definition for SPI_CFG2 register */ +#define I2S_CFG2_IOSWP_SHIFT 15 +#define I2S_CFG2_IOSWP BIT(I2S_CFG2_IOSWP_SHIFT) +#define I2S_CFG2_LSBFRST BIT(23) +#define I2S_CFG2_AFCNTRBIT(31) + +/* Bit definition for SPI_CFG1 register */ +#define I2S_CFG1_FTHVL_SHIFT 5 +#define I2S_CFG1_FTHVL_MASKGENMASK(8, I2S_CFG1_FTHVL_SHIFT) +#define I2S_CFG1_FTHVL_SET(x) ((x) << I2S_CFG1_FTHVL_SHIFT) + +#define I2S_CFG1_TXDMAEN BIT(15) +#define I2S_CFG1_RXDMAEN BIT(14) + +/* Bit definition for SPI2S_IER register */ +#define I2S_IER_RXPIE BIT(0) +#define I2S_IER_TXPIE BIT(1) +#define I2S_IER_DPXPIE BIT(2) +#define I2S_IER_EOTIE BIT(3) +#define I2S_IER_TXTFIE BIT(4) +#define I2S_IER_UDRIE BIT(5) +#define I2S_IER_OVRIE BIT(6) +#define I2S_IER_CRCEIE BIT(7) +#define I2S_IER_TIFREIEBIT(8) +#define I2S_IER_MODFIE BIT(9) +#define I2S_IER_TSERFIEBIT(10) + +/* Bit definition for SPI2S_SR register */ +#define I2S_SR_RXP BIT(0) +#define I2S_SR_TXP BIT(1) +#define I2S_SR_DPXPBIT(2) +#define I2S_SR_EOT BIT(3) +#define I2S_SR_TXTFBIT(4) +#define I2S_SR_UDR BIT(5) +#define I2S_SR_OVR BIT(6) +#define I2S_SR_CRCERR BIT(7) +#define I2S_SR_TIFRE BIT(8) +#define I2S_SR_MODFBIT(9) +#define I2S_SR_TSERF BIT(10) +#define I2S_SR_SUSPBIT(11) +#define I2S_SR_TXC BIT(12) +#define I2S_SR_RXPLVL GENMASK(14, 13) +#define I2S_SR_RXWNE BIT(15) + +#define I2S_SR_MASKGENMASK(15, 0) + +/* Bit definition for SPI_IFCR register */ +#define I2S_IFCR_EOTC BIT(3) +#define I2S_IFCR_TXTFC BIT(4) +#define I2S_IFCR_UDRC BIT(5) +#define I2S_IFCR_OVRC BIT(6) +#define I2S_IFCR_CRCEC BIT(7) +#define I2S_IFCR_TIFRECBIT(8) +#define I2S_IFCR_MODFC BIT(9) +#define I2S_IFCR_TSERFC
Re: [PATCH v4 2/3] ASoC: stm32: Add I2S driver
Hello Mark, Thanks, for applying the patches. On 05/19/2017 07:33 PM, Mark Brown wrote: > On Thu, May 18, 2017 at 05:19:52PM +0200, olivier moysan wrote: > > This looks good so I'm going to apply it, a few things below though - > can you please send a followup patch for the issue with the Kconfig > symbol? > >> --- a/sound/soc/stm/Kconfig >> +++ b/sound/soc/stm/Kconfig >> @@ -5,4 +5,4 @@ menuconfig SND_SOC_STM32 >> select SND_SOC_GENERIC_DMAENGINE_PCM >> select REGMAP_MMIO >> help >> - Say Y if you want to enable ASoC-support for STM32 >> + Say Y if you want to enable ASoC support for STM32 > > This appears to be an unrelated typo fix. > ok >> diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile >> index e466a47..8251931 100644 >> --- a/sound/soc/stm/Makefile >> +++ b/sound/soc/stm/Makefile >> @@ -4,3 +4,7 @@ obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o >> >> snd-soc-stm32-sai-objs := stm32_sai.o >> obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o >> + >> +# I2S >> +snd-soc-stm32-i2s-objs := stm32_i2s.o >> +obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-i2s.o > > Perhaps make this a separate option? It probably makes sense to rename > the option for the SAI at the same time. > ok, I will fix it in a new patch. >> + >> +ret = clk_prepare_enable(i2s->pclk); >> +if (ret) { >> +dev_err(>dev, "Enable pclk failed: %d\n", ret); >> +return ret; >> +} >> + >> +ret = clk_prepare_enable(i2s->i2sclk); >> +if (ret) { >> +dev_err(>dev, "Enable i2sclk failed: %d\n", ret); >> +goto err_pclk_disable; >> +} > > It'd be nice to have runtime PM to disable these when the device is idle > but that's not essential. > Yes, I agree. BRs olivier
Re: [PATCH 14/15] sound: stm32: use devm_of_platform_populate()
Acked-by: Olivier Moysan <olivier.moy...@st.com>
[PATCH 5/7] ASoC: stm32: sai: change stop sequence
Disable SAI before stopping DMA data transfers. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 24b8874..97b69a3 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -629,12 +629,12 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n"); regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, - SAI_XCR1_DMAEN, - (unsigned int)~SAI_XCR1_DMAEN); + SAI_XCR1_SAIEN, + (unsigned int)~SAI_XCR1_SAIEN); ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, -SAI_XCR1_SAIEN, -(unsigned int)~SAI_XCR1_SAIEN); +SAI_XCR1_DMAEN, +(unsigned int)~SAI_XCR1_DMAEN); if (ret < 0) dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); break; -- 1.9.1
[PATCH 6/7] ASoC: stm32: sai: fix clock management
Allow peripheral clock enable/disable on regmap accesses. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 97b69a3..2466af0 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -766,8 +766,8 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return PTR_ERR(base); sai->phys_addr = res->start; - sai->regmap = devm_regmap_init_mmio(>dev, base, - _sai_sub_regmap_config); + sai->regmap = devm_regmap_init_mmio_clk(>dev, "sai_ck", base, + _sai_sub_regmap_config); /* Get direction property */ if (of_property_match_string(np, "dma-names", "tx") >= 0) { -- 1.9.1
[PATCH 3/7] ASoC: stm32: sai: typo fixes
Fix typos in sai driver. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai.c | 2 +- sound/soc/stm/stm32_sai.h | 1 - sound/soc/stm/stm32_sai_sub.c | 28 ++-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 2a27a26..6159d66 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -110,6 +110,6 @@ static int stm32_sai_remove(struct platform_device *pdev) module_platform_driver(stm32_sai_driver); MODULE_DESCRIPTION("STM32 Soc SAI Interface"); -MODULE_AUTHOR("Olivier Moysan, <olivier.moy...@st.com>"); +MODULE_AUTHOR("Olivier Moysan <olivier.moy...@st.com>"); MODULE_ALIAS("platform:st,stm32-sai"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index a801fda..270be93 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -125,7 +125,6 @@ #define SAI_XFRCR_FSOFFBIT(SAI_XFRCR_FSOFF_SHIFT) /** Bit definition for SAI_XSLOTR register **/ - #define SAI_XSLOTR_FBOFF_SHIFT 0 #define SAI_XSLOTR_FBOFF_MASK GENMASK(4, SAI_XSLOTR_FBOFF_SHIFT) #define SAI_XSLOTR_FBOFF_SET(x)((x) << SAI_XSLOTR_FBOFF_SHIFT) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index ae4706c..d7aeed3 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -181,29 +181,29 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) SAI_XCLRFR_MASK); if (flags & SAI_XIMR_OVRUDRIE) { - dev_err(>dev, "IT %s\n", + dev_err(>dev, "IRQ %s\n", STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun"); status = SNDRV_PCM_STATE_XRUN; } if (flags & SAI_XIMR_MUTEDETIE) - dev_dbg(>dev, "IT mute detected\n"); + dev_dbg(>dev, "IRQ mute detected\n"); if (flags & SAI_XIMR_WCKCFGIE) { - dev_err(>dev, "IT wrong clock configuration\n"); + dev_err(>dev, "IRQ wrong clock configuration\n"); status = SNDRV_PCM_STATE_DISCONNECTED; } if (flags & SAI_XIMR_CNRDYIE) - dev_warn(>dev, "IT Codec not ready\n"); + dev_err(>dev, "IRQ Codec not ready\n"); if (flags & SAI_XIMR_AFSDETIE) { - dev_warn(>dev, "IT Anticipated frame synchro\n"); + dev_err(>dev, "IRQ Anticipated frame synchro\n"); status = SNDRV_PCM_STATE_XRUN; } if (flags & SAI_XIMR_LFSDETIE) { - dev_warn(>dev, "IT Late frame synchro\n"); + dev_err(>dev, "IRQ Late frame synchro\n"); status = SNDRV_PCM_STATE_XRUN; } @@ -235,7 +235,7 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int slotr, slotr_mask, slot_size; - dev_dbg(cpu_dai->dev, "masks tx/rx:%#x/%#x, slots:%d, width:%d\n", + dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n", tx_mask, rx_mask, slots, slot_width); switch (slot_width) { @@ -377,7 +377,7 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, ret = clk_prepare_enable(sai->sai_ck); if (ret < 0) { - dev_err(cpu_dai->dev, "failed to enable clock: %d\n", ret); + dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret); return ret; } @@ -497,7 +497,7 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai) SAI_XSLOTR_SLOTEN_SET(sai->slot_mask)); } - dev_dbg(cpu_dai->dev, "slots %d, slot width %d\n", + dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n", sai->slots, sai->slot_width); return 0; @@ -521,7 +521,7 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai) frcr |= SAI_XFRCR_FSALL_SET((fs_active - 1)); frcr_mask = SAI_XFRCR_FRL_MASK | SAI_XFRCR_FSALL_MASK; - dev_dbg(cpu_dai->dev, "frame length %d, frame active %d\n", + dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n", sai->fs_length, fs_active); regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); @@ -784,7 +784,7 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, sai->sai_c
[PATCH 2/2] ASoC: stm32: sai: add h7 support
Add support of SAI on STM32H7 family. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai.c | 13 +- sound/soc/stm/stm32_sai.h | 72 ++--- sound/soc/stm/stm32_sai_sub.c | 92 --- 3 files changed, 155 insertions(+), 22 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 6159d66..f771331 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -27,8 +27,17 @@ #include "stm32_sai.h" +static const struct stm32_sai_conf stm32_sai_conf_f4 = { + .version = SAI_STM32F4, +}; + +static const struct stm32_sai_conf stm32_sai_conf_h7 = { + .version = SAI_STM32H7, +}; + static const struct of_device_id stm32_sai_ids[] = { - { .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 }, + { .compatible = "st,stm32f4-sai", .data = (void *)_sai_conf_f4 }, + { .compatible = "st,stm32h7-sai", .data = (void *)_sai_conf_h7 }, {} }; @@ -52,7 +61,7 @@ static int stm32_sai_probe(struct platform_device *pdev) of_id = of_match_device(stm32_sai_ids, >dev); if (of_id) - sai->version = (enum stm32_sai_version)of_id->data; + sai->conf = (struct stm32_sai_conf *)of_id->data; else return -EINVAL; diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index 270be93..889974dc 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -31,6 +31,10 @@ #define STM_SAI_CLRFR_REGX 0x18 #define STM_SAI_DR_REGX0x1C +/* Sub-block A registers, relative to sub-block A address */ +#define STM_SAI_PDMCR_REGX 0x40 +#define STM_SAI_PDMLY_REGX 0x44 + / Bit definition for SAI_GCR register ***/ #define SAI_GCR_SYNCIN_SHIFT 0 #define SAI_GCR_SYNCIN_MASKGENMASK(1, SAI_GCR_SYNCIN_SHIFT) @@ -75,10 +79,11 @@ #define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT) #define SAI_XCR1_MCKDIV_SHIFT 20 -#define SAI_XCR1_MCKDIV_WIDTH 4 -#define SAI_XCR1_MCKDIV_MASK GENMASK(24, SAI_XCR1_MCKDIV_SHIFT) +#define SAI_XCR1_MCKDIV_WIDTH(x) (((x) == 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) -#define SAI_XCR1_MCKDIV_MAX((1 << SAI_XCR1_MCKDIV_WIDTH) - 1) +#define SAI_XCR1_MCKDIV_MAX(x) ((1 << SAI_XCR1_MCKDIV_WIDTH(x)) - 1) #define SAI_XCR1_OSR_SHIFT 26 #define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT) @@ -178,8 +183,65 @@ #define SAI_XCLRFR_SHIFT 0 #define SAI_XCLRFR_MASKGENMASK(6, SAI_XCLRFR_SHIFT) +/** Bit definition for SAI_PDMCR register **/ +#define SAI_PDMCR_PDMENBIT(0) + +#define SAI_PDMCR_MICNBR_SHIFT 4 +#define SAI_PDMCR_MICNBR_MASK GENMASK(5, SAI_PDMCR_MICNBR_SHIFT) +#define SAI_PDMCR_MICNBR_SET(x)((x) << SAI_PDMCR_MICNBR_SHIFT) + +#define SAI_PDMCR_CKEN1BIT(8) +#define SAI_PDMCR_CKEN2BIT(9) +#define SAI_PDMCR_CKEN3BIT(10) +#define SAI_PDMCR_CKEN4BIT(11) + +/** Bit definition for (SAI_PDMDLY register / +#define SAI_PDMDLY_1L_SHIFT0 +#define SAI_PDMDLY_1L_MASK GENMASK(2, SAI_PDMDLY_1L_SHIFT) +#define SAI_PDMDLY_1L_WIDTH3 + +#define SAI_PDMDLY_1R_SHIFT4 +#define SAI_PDMDLY_1R_MASK GENMASK(6, SAI_PDMDLY_1R_SHIFT) +#define SAI_PDMDLY_1R_WIDTH3 + +#define SAI_PDMDLY_2L_SHIFT8 +#define SAI_PDMDLY_2L_MASK GENMASK(10, SAI_PDMDLY_2L_SHIFT) +#define SAI_PDMDLY_2L_WIDTH3 + +#define SAI_PDMDLY_2R_SHIFT12 +#define SAI_PDMDLY_2R_MASK GENMASK(14, SAI_PDMDLY_2R_SHIFT) +#define SAI_PDMDLY_2R_WIDTH3 + +#define SAI_PDMDLY_3L_SHIFT16 +#define SAI_PDMDLY_3L_MASK GENMASK(18, SAI_PDMDLY_3L_SHIFT) +#define SAI_PDMDLY_3L_WIDTH3 + +#define SAI_PDMDLY_3R_SHIFT20 +#define SAI_PDMDLY_3R_MASK GENMASK(22, SAI_PDMDLY_3R_SHIFT) +#define SAI_PDMDLY_3R_WIDTH3 + +#define SAI_PDMDLY_4L_SHIFT24 +#define SAI_PDMDLY_4L_MASK GENMASK(26, SAI_PDMDLY_4L_SHIFT) +#define SAI_PDMDLY_4L_WIDTH3 + +#define SAI_PDMDLY_4R_SHIFT28 +#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) + enum stm32_sai_version { - SAI_STM32F4 + SAI_STM32F4, + SAI_STM32H7 +}; + +/** + * struct stm32_sai_conf - SAI configuration + * @version: SAI version + */ +struct stm32_sai_conf { + int version; }; /** @@ -194,6 +256,6 @@ struct stm32_sai_data { struct platform_device *pde
[PATCH 2/7] ASoC: stm32: change SAI configuration flag
Use a specific flag for SAI interface instead of common stm32 asoc flag. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 10 +++--- sound/soc/stm/Makefile | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 972970f..d747993 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -1,8 +1,12 @@ -menuconfig SND_SOC_STM32 - tristate "STMicroelectronics STM32 SOC audio support" +menu "STMicroelectronics STM32 SOC audio support" + +config SND_SOC_STM32_SAI + tristate "STM32 SAI interface (Serial Audio Interface) support" depends on ARCH_STM32 || COMPILE_TEST depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help - Say Y if you want to enable ASoC-support for STM32 + Say Y if you want to enable SAI for STM32 + +endmenu diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index e466a47..386ce4b 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -1,6 +1,6 @@ # SAI snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o +obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o +obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o -- 1.9.1
[PATCH 4/7] ASoC: stm32: sai: remove spurious trace
Remove spurious trace in sai driver. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index d7aeed3..24b8874 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -761,9 +761,6 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - dev_err(>dev, "res %pr\n", res); - base = devm_ioremap_resource(>dev, res); if (IS_ERR(base)) return PTR_ERR(base); -- 1.9.1
[PATCH 0/7] ASoC: stm32: sai: misc fixes
This patch-set gathers various fixes on STM32 SAI driver. olivier moysan (7): dt-bindings: stm32: sai: fix DT example ASoC: stm32: change SAI configuration flag ASoC: stm32: sai: typo fixes ASoC: stm32: sai: remove spurious trace ASoC: stm32: sai: change stop sequence ASoC: stm32: sai: fix clock management ASoC: stm32: sai: manage master clock .../devicetree/bindings/sound/st,stm32-sai.txt | 25 -- sound/soc/stm/Kconfig | 10 ++-- sound/soc/stm/Makefile | 4 +- sound/soc/stm/stm32_sai.c | 2 +- sound/soc/stm/stm32_sai.h | 1 - sound/soc/stm/stm32_sai_sub.c | 57 +- 6 files changed, 54 insertions(+), 45 deletions(-) -- 1.9.1
[PATCH 1/7] dt-bindings: stm32: sai: fix DT example
Correct the device tree example. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-sai.txt | 25 +- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index c59a3d7..a0feeed 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -36,6 +36,10 @@ SAI subnodes required properties: - pinctrl-names: should contain only value "default" - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.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"; @@ -46,16 +50,15 @@ sai1: sai1@40015800 { compatible = "st,stm32f4-sai"; #address-cells = <1>; #size-cells = <1>; - ranges; + ranges = <0 0x40015800 0x400>; reg = <0x40015800 0x4>; clocks = < 1 CLK_SAIQ_PDIV>, < 1 CLK_I2SQ_PDIV>; clock-names = "x8k", "x11k"; interrupts = <87>; sai1b: audio-controller@40015824 { - #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-b"; - reg = <0x40015824 0x1C>; + reg = <0x24 0x1C>; clocks = < 1 CLK_SAI2>; clock-names = "sai_ck"; dmas = < 5 0 0x400 0x0>; @@ -63,18 +66,10 @@ sai1: sai1@40015800 { pinctrl-names = "default"; pinctrl-0 = <_sai1b>; - ports { - #address-cells = <1>; - #size-cells = <0>; - - sai1b_port: port@0 { - reg = <0>; - cpu_endpoint: endpoint { - remote-endpoint = <_endpoint>; - audio-graph-card,format = "i2s"; - audio-graph-card,bitclock-master = <_endpoint>; - audio-graph-card,frame-master = <_endpoint>; - }; + sai1b_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + format = "i2s"; }; }; }; -- 1.9.1
[PATCH 1/2] dt-bindings: stm32: add h7 support for sai
Document device tree bindings for STM32H7 SAI. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-sai.txt | 18 +- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index a0feeed..f1c5ae5 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -6,7 +6,7 @@ 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" + - 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. @@ -47,24 +47,24 @@ sound_card { }; sai1: sai1@40015800 { - compatible = "st,stm32f4-sai"; + compatible = "st,stm32h7-sai"; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x40015800 0x400>; reg = <0x40015800 0x4>; - clocks = < 1 CLK_SAIQ_PDIV>, < 1 CLK_I2SQ_PDIV>; + clocks = < PLL1_Q>, < PLL2_P>; clock-names = "x8k", "x11k"; interrupts = <87>; - sai1b: audio-controller@40015824 { - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1C>; - clocks = < 1 CLK_SAI2>; + sai1a: audio-controller@40015804 { + compatible = "st,stm32-sai-sub-a"; + reg = <0x4 0x1C>; + clocks = < SAI1_CK>; clock-names = "sai_ck"; - dmas = < 5 0 0x400 0x0>; + dmas = < 1 87 0x400 0x0>; dma-names = "tx"; pinctrl-names = "default"; - pinctrl-0 = <_sai1b>; + pinctrl-0 = <_sai1a>; sai1b_port: port { cpu_endpoint: endpoint { -- 1.9.1
[PATCH 7/7] ASoC: stm32: sai: manage master clock
Disable master clock by default, and activate it only when requested. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 2466af0..ce48c02 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -220,8 +220,15 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); + int ret; if ((dir == SND_SOC_CLOCK_OUT) && sai->master) { + ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, +SAI_XCR1_NODIV, +(unsigned int)~SAI_XCR1_NODIV); + if (ret < 0) + return ret; + sai->mclk_rate = freq; dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq); } @@ -356,6 +363,10 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) } cr1_mask |= SAI_XCR1_SLAVE; + /* do not generate master by default */ + cr1 |= SAI_XCR1_NODIV; + cr1_mask |= SAI_XCR1_NODIV; + ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); if (ret < 0) { dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); @@ -652,6 +663,9 @@ 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); + clk_disable_unprepare(sai->sai_ck); sai->substream = NULL; } -- 1.9.1
[PATCH 0/2] ASoC: stm32: sai: Add H7 support
This patch-set adds support of the Serial Audio Interface (SAI) IP on H7 STM32 platform family. olivier moysan (2): dt-bindings: stm32: add h7 support for sai ASoC: stm32: sai: add h7 support .../devicetree/bindings/sound/st,stm32-sai.txt | 18 ++--- sound/soc/stm/stm32_sai.c | 13 ++- sound/soc/stm/stm32_sai.h | 72 +++-- sound/soc/stm/stm32_sai_sub.c | 92 ++ 4 files changed, 164 insertions(+), 31 deletions(-) -- 1.9.1
[PATCH 2/2] ASoC: stm32: Add SPDIFRX support
Add SPDIFRX support to STM32. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 10 + sound/soc/stm/Makefile| 4 + sound/soc/stm/stm32_spdifrx.c | 998 ++ sound/soc/stm/stm32_spdifrx.h | 224 ++ 4 files changed, 1236 insertions(+) create mode 100644 sound/soc/stm/stm32_spdifrx.c create mode 100644 sound/soc/stm/stm32_spdifrx.h diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index d747993..45c05a3 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -9,4 +9,14 @@ config SND_SOC_STM32_SAI help Say Y if you want to enable SAI for STM32 +config SND_SOC_STM32_SPDIFRX + tristate "STM32 S/PDIF receiver (SPDIFRX) support" + depends on ARCH_STM32 || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + select SND_SOC_SPDIF + help + Say Y if you want to enable S/PDIF capture for STM32 + endmenu diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index 386ce4b..c6a8e72 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o + +# SPDIFRX +snd-soc-stm32-spdifrx-objs := stm32_spdifrx.o +obj-$(CONFIG_SND_SOC_STM32_SPDIFRX) += snd-soc-stm32-spdifrx.o diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c new file mode 100644 index 000..4e4250b --- /dev/null +++ b/sound/soc/stm/stm32_spdifrx.c @@ -0,0 +1,998 @@ +/* + * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver. + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Olivier Moysan <olivier.moy...@st.com> for STMicroelectronics. + * + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* SPDIF-rx Register Map */ +#define STM32_SPDIFRX_CR 0x00 +#define STM32_SPDIFRX_IMR 0x04 +#define STM32_SPDIFRX_SR 0x08 +#define STM32_SPDIFRX_IFCR 0x0C +#define STM32_SPDIFRX_DR 0x10 +#define STM32_SPDIFRX_CSR 0x14 +#define STM32_SPDIFRX_DIR 0x18 + +/* Bit definition for SPDIF_CR register */ +#define SPDIFRX_CR_SPDIFEN_SHIFT 0 +#define SPDIFRX_CR_SPDIFEN_MASKGENMASK(1, SPDIFRX_CR_SPDIFEN_SHIFT) +#define SPDIFRX_CR_SPDIFENSET(x) ((x) << SPDIFRX_CR_SPDIFEN_SHIFT) + +#define SPDIFRX_CR_RXDMAEN BIT(2) +#define SPDIFRX_CR_RXSTEO BIT(3) + +#define SPDIFRX_CR_DRFMT_SHIFT 4 +#define SPDIFRX_CR_DRFMT_MASK GENMASK(5, SPDIFRX_CR_DRFMT_SHIFT) +#define SPDIFRX_CR_DRFMTSET(x) ((x) << SPDIFRX_CR_DRFMT_SHIFT) + +#define SPDIFRX_CR_PMSKBIT(6) +#define SPDIFRX_CR_VMSKBIT(7) +#define SPDIFRX_CR_CUMSK BIT(8) +#define SPDIFRX_CR_PTMSK BIT(9) +#define SPDIFRX_CR_CBDMAEN BIT(10) +#define SPDIFRX_CR_CHSEL_SHIFT 11 +#define SPDIFRX_CR_CHSEL BIT(SPDIFRX_CR_CHSEL_SHIFT) + +#define SPDIFRX_CR_NBTR_SHIFT 12 +#define SPDIFRX_CR_NBTR_MASK GENMASK(13, SPDIFRX_CR_NBTR_SHIFT) +#define SPDIFRX_CR_NBTRSET(x) ((x) << SPDIFRX_CR_NBTR_SHIFT) + +#define SPDIFRX_CR_WFA BIT(14) + +#define SPDIFRX_CR_INSEL_SHIFT 16 +#define SPDIFRX_CR_INSEL_MASK GENMASK(18, PDIFRX_CR_INSEL_SHIFT) +#define SPDIFRX_CR_INSELSET(x) ((x) << SPDIFRX_CR_INSEL_SHIFT) + +#define SPDIFRX_CR_CKSEN_SHIFT 20 +#define SPDIFRX_CR_CKSEN BIT(20) +#define SPDIFRX_CR_CKSBKPENBIT(21) + +/* Bit definition for SPDIFRX_IMR register */ +#define SPDIFRX_IMR_RXNEI BIT(0) +#define SPDIFRX_IMR_CSRNEIEBIT(1) +#define SPDIFRX_IMR_PERRIE BIT(2) +#define SPDIFRX_IMR_OVRIE BIT(3) +#define SPDIFRX_IMR_SBLKIE BIT(4) +#define SPDIFRX_IMR_SYNCDIEBIT(5) +#define SPDIFRX_IMR_IFEIE BIT(6) + +#define SPDIFRX_XIMR_MASK GENMASK(6, 0) + +/* Bit definition for SPDIFRX_SR register */ +#define SPDIFRX_SR_RXNEBIT(0) +#define SPDIFRX_SR_CSRNE BIT(1) +#define SPDIFRX_SR_PERRBIT(2) +#define SPDIFRX_SR_OVR BIT(3) +#define SPDIFRX_SR_SBD BIT(4) +#define SPDIFRX_SR_SYNCD BIT(5) +#define SPDIFRX_SR_FERRBIT(6) +#define SPDIFRX_SR_SERRBIT(7) +#define SPDIFRX_SR_TERRBIT(8) + +#define SPDIFRX_SR_WIDTH5_SHIFT16 +#define SPDIFRX_SR_WIDTH5_MAS
[PATCH 1/2] dt-bindings: Document the STM32 SPDIFRX interface
This adds documentation of device tree bindings for the STM32 SPDIFRX interface. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- .../devicetree/bindings/sound/st,stm32-spdifrx.txt | 56 ++ 1 file changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt diff --git a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt new file mode 100644 index 000..33826f2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt @@ -0,0 +1,56 @@ +STMicroelectronics STM32 S/PDIF receiver (SPDIFRX). + +The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with +IEC-60958 and IEC-61937. + +Required properties: + - compatible: should be "st,stm32h7-spdifrx" + - reg: cpu DAI IP base address and size + - clocks: must contain an entry for kclk (used as S/PDIF signal reference) + - clock-names: must contain "kclk" + - interrupts: cpu DAI interrupt line + - dmas: DMA specifiers for audio data DMA and iec control flow DMA +See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt + - dma-names: two dmas have to be defined, "rx" and "rx-ctrl" + +Optional properties: + - resets: Reference to a reset controller asserting the SPDIFRX + +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: +spdifrx: spdifrx@40004000 { + compatible = "st,stm32h7-spdifrx"; + reg = <0x40004000 0x400>; + clocks = < SPDIFRX_CK>; + clock-names = "kclk"; + interrupts = <97>; + dmas = < 2 93 0x400 0x0>, + < 3 94 0x400 0x0>; + dma-names = "rx", "rx-ctrl"; + pinctrl-0 = <_pins>; + pinctrl-names = "default"; + + spdifrx_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; + +spdif_in: spdif-in { + compatible = "linux,spdif-dir"; + + codec_port: port { + codec_endpoint: endpoint { + remote-endpoint = <_endpoint>; + }; + }; +}; + +soundcard { + compatible = "audio-graph-card"; + dais = <_port>; +}; -- 1.9.1
[PATCH 0/2] ASoC: stm32: add SPDIFRX driver
This patch-set handles the SPDIFRX on STM32 platforms. The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with IEC-60958 and IEC-61937 standards. SPDIFRX uses two DMA channels: - one DMA channel for S/PDIF data stream. - one DMA channel for control flow (channel status and user data bits). DMA is used for control flow instead of interrupts to get better performances, as channel status and user data are retrieved byte per byte. Note: This patch-set depends on "change SAI configuration flag" patch, which introduces a change on Kconfig file. olivier moysan (2): dt-bindings: Document the STM32 SPDIFRX interface ASoC: stm32: Add SPDIFRX support .../devicetree/bindings/sound/st,stm32-spdifrx.txt | 56 ++ sound/soc/stm/Kconfig | 10 + sound/soc/stm/Makefile | 4 + sound/soc/stm/stm32_spdifrx.c | 998 + sound/soc/stm/stm32_spdifrx.h | 224 + 5 files changed, 1292 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt create mode 100644 sound/soc/stm/stm32_spdifrx.c create mode 100644 sound/soc/stm/stm32_spdifrx.h -- 1.9.1
[PATCH 1/1] ASoC: stm32: change configuration flag
Use a specific flag for SAI and I2S interfaces, instead of common flag. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 19 --- sound/soc/stm/Makefile | 6 +++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index a6372de..23600a5 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -1,8 +1,21 @@ -menuconfig SND_SOC_STM32 - tristate "STMicroelectronics STM32 SOC audio support" +menu "STMicroelectronics STM32 SOC audio support" + +config SND_SOC_STM32_SAI + tristate "STM32 SAI interface (Serial Audio Interface) support" depends on ARCH_STM32 || COMPILE_TEST depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO help - Say Y if you want to enable ASoC support for STM32 + Say Y if you want to enable SAI for STM32 + +config SND_SOC_STM32_I2S + tristate "STM32 I2S interface (SPI/I2S block) support" + depends on ARCH_STM32 || COMPILE_TEST + depends on SND_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y if you want to enable I2S for STM32 + +endmenu diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile index 8251931..4140c67 100644 --- a/sound/soc/stm/Makefile +++ b/sound/soc/stm/Makefile @@ -1,10 +1,10 @@ # SAI snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o +obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai-sub.o snd-soc-stm32-sai-objs := stm32_sai.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o +obj-$(CONFIG_SND_SOC_STM32_SAI) += snd-soc-stm32-sai.o # I2S snd-soc-stm32-i2s-objs := stm32_i2s.o -obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-i2s.o +obj-$(CONFIG_SND_SOC_STM32_I2S) += snd-soc-stm32-i2s.o -- 1.9.1
Re: [PATCH 2/7] ASoC: stm32: change SAI configuration flag
Hello Mark, On 06/16/2017 07:49 PM, Mark Brown wrote: > On Fri, Jun 16, 2017 at 02:15:29PM +0200, olivier moysan wrote: >> Use a specific flag for SAI interface instead >> of common stm32 asoc flag. > > This doesn't apply against current code, please check and resend. > I pushed this patch-set on stm topic branch. I resend a patch on next, to fix the merge issue. Best regards olivier
Re: [PATCH v3 1/2] ASoC: stm32: add bindings for SAI
Hello Rob, On 04/28/2017 10:53 PM, Rob Herring wrote: > On Mon, Apr 10, 2017 at 05:19:55PM +0200, olivier moysan wrote: >> This patch adds documentation of device tree bindings for the >> STM32 SAI ASoC driver. >> >> Signed-off-by: olivier moysan <olivier.moy...@st.com> >> --- >> .../devicetree/bindings/sound/st,stm32-sai.txt | 89 >> ++ >> 1 file changed, 89 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt >> >> diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt >> b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt >> new file mode 100644 >> index 000..c59a3d7 >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt >> @@ -0,0 +1,89 @@ >> +STMicroelectronics STM32 Serial Audio Interface (SAI). > > [...] > >> +sai1b: audio-controller@40015824 { >> +#sound-dai-cells = <0>; >> +compatible = "st,stm32-sai-sub-b"; >> +reg = <0x40015824 0x1C>; >> +clocks = < 1 CLK_SAI2>; >> +clock-names = "sai_ck"; >> +dmas = < 5 0 0x400 0x0>; >> +dma-names = "tx"; >> +pinctrl-names = "default"; >> +pinctrl-0 = <_sai1b>; >> + >> +ports { >> +#address-cells = <1>; >> +#size-cells = <0>; >> + >> +sai1b_port: port@0 { >> +reg = <0>; >> +cpu_endpoint: endpoint { >> +remote-endpoint = <_endpoint>; >> +audio-graph-card,format = "i2s"; >> +audio-graph-card,bitclock-master = >> <_endpoint>; >> +audio-graph-card,frame-master = >> <_endpoint>; > > These property names are wrong. > I have taken into account this comment (and previous ones). They will be included in next update of this patch set. >> +}; >> +}; >> +}; >> +}; >> +}; >> + >> +audio-codec { >> +codec_port: port { >> +codec_endpoint: endpoint { >> +remote-endpoint = <_endpoint>; >> +}; >> +}; >> +}; >> -- >> 1.9.1 >> Best regards Olivier
[PATCH 1/3] ASoC: stm32: fix sync property description in SAI bindings
SAI sync property must be described in SAI subnodes section, as it is a property of child node. This patch fixes commit 14f0e5f8d97e632695d92f41f2e91d10d8005d47 "ASoC: stm32: Add synchronization to SAI bindings". Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index 1f9cd70..b1acc1a 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -20,11 +20,6 @@ Required properties: Optional properties: - resets: Reference to a reset controller asserting the SAI - - st,sync: specify synchronization mode. - By default SAI sub-block is in asynchronous mode. - This property sets SAI sub-block as slave of another SAI sub-block. - Must contain the phandle and index of the sai sub-block providing - the synchronization. SAI subnodes: Two subnodes corresponding to SAI sub-block instances A et B can be defined. @@ -44,6 +39,13 @@ SAI subnodes required properties: - pinctrl-names: should contain only value "default" - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt +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. + 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. -- 1.9.1
[PATCH 0/3] ASoC: stm32: sai: fixes related to synchro feature
Fix sai binding and simplify code related to synchro feature. This change allows to remove stm32_sai_remove() function and use devm_of_platform_populate(). Olivier Moysan (3): ASoC: stm32: fix sync property description in SAI bindings ASoC: stm32: sai: simplify sync modes management ASoC: stm32: sai: use devm_of_platform_populate() .../devicetree/bindings/sound/st,stm32-sai.txt | 12 ++- sound/soc/stm/stm32_sai.c | 114 - 2 files changed, 29 insertions(+), 97 deletions(-) -- 1.9.1
[PATCH 2/3] ASoC: stm32: sai: simplify sync modes management
Use function of_find_device_by_node() to retrieve SAI synchro provider device and private data. This allows to remove registration of probed SAI in a linked list. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai.c | 105 ++ 1 file changed, 22 insertions(+), 83 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index d6f71a3..0a1f064 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -28,16 +28,6 @@ #include "stm32_sai.h" -static LIST_HEAD(sync_providers); -static DEFINE_MUTEX(sync_mutex); - -struct sync_provider { - struct list_head link; - struct device_node *node; - int (*sync_conf)(void *data, int synco); - void *data; -}; - static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = SAI_STM32F4, }; @@ -70,9 +60,8 @@ static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci) return 0; } -static int stm32_sai_sync_conf_provider(void *data, int synco) +static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco) { - struct stm32_sai_data *sai = (struct stm32_sai_data *)data; u32 prev_synco; int ret; @@ -103,73 +92,34 @@ static int stm32_sai_sync_conf_provider(void *data, int synco) return 0; } -static int stm32_sai_set_sync_provider(struct device_node *np, int synco) +static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, + struct device_node *np_provider, + int synco, int synci) { - struct sync_provider *provider; + struct platform_device *pdev = of_find_device_by_node(np_provider); + struct stm32_sai_data *sai_provider; int ret; - mutex_lock(_mutex); - list_for_each_entry(provider, _providers, link) { - if (provider->node == np) { - ret = provider->sync_conf(provider->data, synco); - mutex_unlock(_mutex); - return ret; - } + if (!pdev) { + dev_err(_client->pdev->dev, + "Device not found for node %s\n", np_provider->name); + return -ENODEV; } - mutex_unlock(_mutex); - /* SAI sync provider not found */ - return -ENODEV; -} - -static int stm32_sai_set_sync(struct stm32_sai_data *sai, - struct device_node *np_provider, - int synco, int synci) -{ - int ret; + sai_provider = platform_get_drvdata(pdev); + if (!sai_provider) { + dev_err(_client->pdev->dev, + "SAI sync provider data not found\n"); + return -EINVAL; + } /* Configure sync client */ - stm32_sai_sync_conf_client(sai, synci); + ret = stm32_sai_sync_conf_client(sai_client, synci); + if (ret < 0) + return ret; /* Configure sync provider */ - ret = stm32_sai_set_sync_provider(np_provider, synco); - - return ret; -} - -static int stm32_sai_sync_add_provider(struct platform_device *pdev, - void *data) -{ - struct sync_provider *sp; - - sp = devm_kzalloc(>dev, sizeof(*sp), GFP_KERNEL); - if (!sp) - return -ENOMEM; - - sp->node = of_node_get(pdev->dev.of_node); - sp->data = data; - sp->sync_conf = _sai_sync_conf_provider; - - mutex_lock(_mutex); - list_add(>link, _providers); - mutex_unlock(_mutex); - - return 0; -} - -static void stm32_sai_sync_del_provider(struct device_node *np) -{ - struct sync_provider *sp; - - mutex_lock(_mutex); - list_for_each_entry(sp, _providers, link) { - if (sp->node == np) { - list_del(>link); - of_node_put(sp->node); - break; - } - } - mutex_unlock(_mutex); + return stm32_sai_sync_conf_provider(sai_provider, synco); } static int stm32_sai_probe(struct platform_device *pdev) @@ -179,7 +129,6 @@ static int stm32_sai_probe(struct platform_device *pdev) struct reset_control *rst; struct resource *res; const struct of_device_id *of_id; - int ret; sai = devm_kzalloc(>dev, sizeof(*sai), GFP_KERNEL); if (!sai) @@ -231,27 +180,17 @@ static int stm32_sai_probe(struct platform_device *pdev) reset_control_deassert(rst); } - ret = stm32_sai_sync_add_provider(pdev, sai); - if (ret < 0) - return ret; - sai->set_sync = _sai_set_sync; - sai->pdev = pdev; + sai->set_sync = _sai_set_sync; platform_set_drvdata(pdev, sai); - ret = of_pla
[PATCH 3/3] ASoC: stm32: sai: use devm_of_platform_populate()
Use devm_of_platform_populate() instead of of_platform_depopulate() to simplify driver code. Signed-off-by: Benjamin Gaignard <benjamin.gaign...@linaro.org> Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai.c | 11 +-- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 0a1f064..d743b7d 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -124,7 +124,6 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, static int stm32_sai_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct stm32_sai_data *sai; struct reset_control *rst; struct resource *res; @@ -184,14 +183,7 @@ static int stm32_sai_probe(struct platform_device *pdev) sai->set_sync = _sai_set_sync; platform_set_drvdata(pdev, sai); - return of_platform_populate(np, NULL, NULL, >dev); -} - -static int stm32_sai_remove(struct platform_device *pdev) -{ - of_platform_depopulate(>dev); - - return 0; + return devm_of_platform_populate(>dev); } MODULE_DEVICE_TABLE(of, stm32_sai_ids); @@ -202,7 +194,6 @@ static int stm32_sai_remove(struct platform_device *pdev) .of_match_table = stm32_sai_ids, }, .probe = stm32_sai_probe, - .remove = stm32_sai_remove, }; module_platform_driver(stm32_sai_driver); -- 1.9.1
[RFC PATCH 1/2] ASoC: add support of mclk clock providers in wm8894 driver
Wolfson wm8994 codec bindings exposes MCLK1 and MCLK1 clocks. This patch adds support of MCLK1 and MCLK2 in mfd driver. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- drivers/mfd/wm8994-core.c| 9 + include/linux/mfd/wm8994/pdata.h | 6 ++ 2 files changed, 15 insertions(+) diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 953d079..f1ff9d8 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -12,6 +12,7 @@ * */ +#include #include #include #include @@ -310,6 +311,14 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) if (pdata->ldo[1].enable < 0) pdata->ldo[1].enable = 0; + pdata->mclk1 = devm_clk_get(wm8994->dev, "MCLK1"); + if (IS_ERR(pdata->mclk1)) + pdata->mclk1 = NULL; + + pdata->mclk2 = devm_clk_get(wm8994->dev, "MCLK2"); + if (IS_ERR(pdata->mclk2)) + pdata->mclk2 = NULL; + return 0; } #else diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index 90c6052..8037d26 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -233,6 +233,12 @@ struct wm8994_pdata { * GPIO for the IRQ pin if host only supports edge triggering */ int irq_gpio; + + /* MCLK1 clock provider */ + struct clk *mclk1; + + /* MCLK2 clock provider */ + struct clk *mclk2; }; #endif -- 1.9.1
[RFC PATCH 0/2] select master clock in wm8994 driver based on DT clocks configuration
Hello, This RFC follows a previous RFC related to master clock issues with Wolfson wm8994 codec: http://mailman.alsa-project.org/pipermail/alsa-devel/2017-March/118834.html This RFC provides a new proposal regarding master clock selection in wm8994 driver. Below is a reminder of the problem: Use case: CPU DAI and codec are managed through audio graph card. Wolson codec wm8994 is set as slave of CPU DAI and CPU DAI feeds codec with master clock. Master clock is derived from mclk-fs property and provided to CPU DAI and codec through snd_soc_dai_set_sysclk API. Analysis: The audio graph card sets clock id to 0, while wm8994 codec driver expects a clock id in the range [1..4]. (MCLK1, MCLK2 ..) Proposal: Wolfson wm8994 codec bindings exposes MCLK1 and MCLK1 clocks. It seems that these clocks are not supported in wm8994 driver, yet. First patch adds support of these clocks. Second patch sets master clock according to clocks provided in DT. The patch assumes that MCLK1 and MCLK2 are linked to aif1 and aif2 interfaces respectively. If MCLKx is defined, is it used as source clock for aifx interface. Otherwise clock id parameter is used as usual. By default clock rate is requested from clock framework. This is not convenient, when mclk clock frequency is computed for mclk-fs ratio, as codec set_sysclk() is called before cpu set_sysclk() callback. In this case frequency provided by set_sysclk() must be used. So, if MCLKx rate is 0, frequency parameter provided by wm8994_set_dai_sysclk() is used. I have a limited view of potential side effects here, so any comments are welcome. If some adaptations are required to make this change more generic, please let me know. Regards Olivier Olivier Moysan (2): ASoC: add support of mclk clock providers in wm8894 driver ASoC: select sysclk clock from mlck clock provider in wm8994 driver drivers/mfd/wm8994-core.c| 9 + include/linux/mfd/wm8994/pdata.h | 6 ++ sound/soc/codecs/wm8994.c| 20 +++- 3 files changed, 34 insertions(+), 1 deletion(-) -- 1.9.1
[RFC PATCH 2/2] ASoC: select sysclk clock from mlck clock provider in wm8994 driver
When defined in device tree, MCLK1 and MCLK2 are used as sysclk for aif1 and aif2 interfaces respectively. If clock rate is let 0, the frequency provided by wm8994_set_dai_sysclk() is used instead. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/codecs/wm8994.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 21ffd64..7a84e37 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -11,6 +11,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -2376,18 +2377,35 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, { struct snd_soc_codec *codec = dai->codec; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = >pdata; + unsigned long rate; int i; switch (dai->id) { case 1: + if (pdata->mclk1) { + rate = clk_get_rate(pdata->mclk1); + if (rate) + freq = (unsigned int)rate; + clk_id = WM8994_SYSCLK_MCLK1; + } + break; case 2: + if (pdata->mclk2) { + rate = clk_get_rate(pdata->mclk2); + if (rate) + freq = (unsigned int)rate; + clk_id = WM8994_SYSCLK_MCLK2; + } break; - default: /* AIF3 shares clocking with AIF1/2 */ return -EINVAL; } + dev_info(codec->dev, "%s:.clock id %d\n", __func__, clk_id); + switch (clk_id) { case WM8994_SYSCLK_MCLK1: wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1; -- 1.9.1
Re: [RFC PATCH 2/2] ASoC: select sysclk clock from mlck clock provider in wm8994 driver
Hello Mark, Thanks for your comment. On 12/14/2017 06:36 PM, Mark Brown wrote: > On Thu, Dec 14, 2017 at 05:53:58PM +0100, Olivier Moysan wrote: >> When defined in device tree, MCLK1 and MCLK2 are used >> as sysclk for aif1 and aif2 interfaces respectively. > > That's not a valid assumption as far as I remember? The AIFs can use > either MCLK depending on the system configuration I think. > You are right. wm8994 allows to select either MCLK for each AIF. From this point of view, the current patch is too limiting. MCLK information in DT allows to enforce MCLK use, but an additionnal information is required to determine AIF MCLK assignment. Available properties in codec DAI node, such as clocks property, cannot help here. Maybe a DAPM linked to a control is a better way to select AIF source, When source is not provided by clk_id in wm8994_set_dai_sysclk(). In this case, wm8994_set_dai_sysclk() would only have to check if clock source is not already set. Please let me know if this option sounds better to you. >> If clock rate is let 0, the frequency provided by >> wm8994_set_dai_sysclk() is used instead. > > I'd expect this the other way around, if we didn't specify a frequency > then read it from the input otherwise try to use clk_set_rate() to > propagate things up. > If I implement a control to select the AIF source, I will drop the code related to mclk clock provider. Regards Olivier
Re: [RFC PATCH 2/2] ASoC: select sysclk clock from mlck clock provider in wm8994 driver
Hello Mark, On 12/19/2017 10:35 AM, Mark Brown wrote: > On Fri, Dec 15, 2017 at 03:15:22PM +0000, Olivier MOYSAN wrote: > >> You are right. wm8994 allows to select either MCLK for each AIF. >> From this point of view, the current patch is too limiting. >> MCLK information in DT allows to enforce MCLK use, but an additionnal >> information is required to determine AIF MCLK assignment. >> Available properties in codec DAI node, such as clocks property, cannot >> help here. > >> Maybe a DAPM linked to a control is a better way to select AIF source, >> When source is not provided by clk_id in wm8994_set_dai_sysclk(). >> In this case, wm8994_set_dai_sysclk() would only have to check >> if clock source is not already set. > >> Please let me know if this option sounds better to you. > > What are you trying to accomplish here? You appear to be trying to move > the system clocking configuration from the machine driver to the CODEC > which is not how things are supposed to work. > As a generic machine, simple or audio graph cards are not able to manage codec clock muxing. If we exclude the management of muxing through codec controls, the remaining solution is to handle it fully through clock framework. The current patch only supports a limited range of muxing capabilities of the codec. To have a full management of the muxing, I think it is necessary to add a device tree node for each codec interface and to define an aif clock in these nodes. Then parent clock assignment of these aif clocks would allow to handle the muxing. Please, let me known if is this the right direction for you. BRs olivier
[PATCH 2/2] ASoC: stm32: spdifrx: fix control DMA error management
Fix DMA channel request error handling. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_spdifrx.c | 15 +++ 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index d7dbe84..b9bdefc 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -392,6 +392,12 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev, { int ret; + spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); + if (IS_ERR(spdifrx->ctrl_chan)) { + dev_err(dev, "dma_request_slave_channel failed\n"); + return PTR_ERR(spdifrx->ctrl_chan); + } + spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), GFP_KERNEL); if (!spdifrx->dmab) @@ -406,12 +412,6 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev, return ret; } - spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); - if (!spdifrx->ctrl_chan) { - dev_err(dev, "dma_request_slave_channel failed\n"); - return -EINVAL; - } - spdifrx->slave_config.direction = DMA_DEV_TO_MEM; spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr + STM32_SPDIFRX_CSR); @@ -423,7 +423,6 @@ static int stm32_spdifrx_dma_ctrl_register(struct device *dev, >slave_config); if (ret < 0) { dev_err(dev, "dmaengine_slave_config returned error %d\n", ret); - dma_release_channel(spdifrx->ctrl_chan); spdifrx->ctrl_chan = NULL; } @@ -962,7 +961,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) return 0; error: - if (spdifrx->ctrl_chan) + if (!IS_ERR(spdifrx->ctrl_chan)) dma_release_channel(spdifrx->ctrl_chan); if (spdifrx->dmab) snd_dma_free_pages(spdifrx->dmab); -- 1.9.1
[PATCH 1/2] ASoC: stm32: spdifrx: fix 16 bits capture
Change DMA bus width to manage properly 16 bits packed format. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_spdifrx.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 84cc567..d7dbe84 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -750,17 +750,21 @@ static int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream, switch (data_size) { case 16: fmt = SPDIFRX_DRFMT_PACKED; - spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; break; case 32: fmt = SPDIFRX_DRFMT_LEFT; - spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; break; default: dev_err(>pdev->dev, "Unexpected data format\n"); return -EINVAL; } + /* +* Set buswidth to 4 bytes for all data formats. +* Packed format: transfer 2 x 2 bytes samples +* Left format: transfer 1 x 3 bytes samples + 1 dummy byte +*/ + spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; snd_soc_dai_init_dma_data(cpu_dai, NULL, >dma_params); return regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, -- 1.9.1
[PATCH 0/2] ASoC: stm32: spdifrx: DMA management fixes
This patch-set gathers DMA management fixes for STM32 SPDIFRX. Olivier Moysan (2): ASoC: stm32: spdifrx: fix 16 bits capture ASoC: stm32: spdifrx: fix control DMA error management sound/soc/stm/stm32_spdifrx.c | 23 +-- 1 file changed, 13 insertions(+), 10 deletions(-) -- 1.9.1
Re: [INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
Hello Takashi, Sorry for late answer. I was OoO. Ok, I will add a protection on sai->substream accesses. Best regards Olivier On 10/26/2017 05:32 PM, Takashi Iwai wrote: > On Thu, 19 Oct 2017 15:03:20 +0200, > Olivier Moysan wrote: >> >> Add check on substream validity. >> >> Signed-off-by: Olivier Moysan <olivier.moy...@st.com> >> --- >> sound/soc/stm/stm32_sai_sub.c | 12 >> 1 file changed, 8 insertions(+), 4 deletions(-) >> >> diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c >> index 2af397d..815ef10 100644 >> --- a/sound/soc/stm/stm32_sai_sub.c >> +++ b/sound/soc/stm/stm32_sai_sub.c >> @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device >> *dev, unsigned int reg) >> static irqreturn_t stm32_sai_isr(int irq, void *devid) >> { >> struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; >> -struct snd_pcm_substream *substream = sai->substream; >> struct platform_device *pdev = sai->pdev; >> unsigned int sr, imr, flags; >> snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING; >> @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) >> regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, >> SAI_XCLRFR_MASK); >> >> +if (!sai->substream) { >> +dev_err(>dev, "Device stopped. Spurious IRQ 0x%x\n", sr); >> +return IRQ_NONE; >> +} >> + >> if (flags & SAI_XIMR_OVRUDRIE) { >> dev_err(>dev, "IRQ %s\n", >> STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun"); >> @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) >> } >> >> if (status != SNDRV_PCM_STATE_RUNNING) { >> -snd_pcm_stream_lock(substream); >> -snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); >> -snd_pcm_stream_unlock(substream); >> +snd_pcm_stream_lock(sai->substream); >> +snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN); >> +snd_pcm_stream_unlock(sai->substream); > > Actually changing to sai->substream opens a race, so this chunk is a > bad move, at least. We have no protection of sai->substream in this > context, thus it can hit a NULL dereference... > > > thanks, > > Takashi >
[PATCH 2/2] ASoC: add mclk-fs support to audio graph card
Add mclk-fs support to audio graph card as it was previously implemented in simple card. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/generic/audio-graph-card.c | 47 ++-- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 488c52f..1b61642 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -29,7 +29,9 @@ struct graph_card_data { struct graph_dai_props { struct asoc_simple_dai cpu_dai; struct asoc_simple_dai codec_dai; + unsigned int mclk_fs; } *dai_props; + unsigned int mclk_fs; struct snd_soc_dai_link *dai_link; struct gpio_desc *pa_gpio; }; @@ -95,9 +97,43 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) asoc_simple_card_clk_disable(_props->codec_dai); } +static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, +struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); + unsigned int mclk, mclk_fs = 0; + int ret = 0; + + if (priv->mclk_fs) + mclk_fs = priv->mclk_fs; + else if (dai_props->mclk_fs) + mclk_fs = dai_props->mclk_fs; + + if (mclk_fs) { + mclk = params_rate(params) * mclk_fs; + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, +SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) + goto err; + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, +SND_SOC_CLOCK_OUT); + if (ret && ret != -ENOTSUPP) + goto err; + } + return 0; +err: + return ret; +} + static const struct snd_soc_ops asoc_graph_card_ops = { .startup = asoc_graph_card_startup, .shutdown = asoc_graph_card_shutdown, + .hw_params = asoc_graph_card_hw_params, }; static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) @@ -146,10 +182,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, if (ret < 0) goto dai_link_of_err; - /* -* we need to consider "mclk-fs" around here -* see simple-card -*/ + of_property_read_u32(rcpu_ep, "mclk-fs", _props->mclk_fs); ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); if (ret < 0) @@ -217,10 +250,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) if (ret < 0) return ret; - /* -* we need to consider "mclk-fs" around here -* see simple-card -*/ + /* Factor to mclk, used in hw_params() */ + of_property_read_u32(node, "mclk-fs", >mclk_fs); of_for_each_phandle(, rc, node, "dais", NULL, 0) { ret = asoc_graph_card_dai_link_of(it.node, priv, idx++); -- 1.9.1
[PATCH 0/2] ASoC: add mclk-fs support to audio graph card
The aim of these patches is to port mclk-fs property to audio graph card, as originally implemented in simple card. Olivier Moysan (2): ASoC: add mclk-fs to audio graph card binding ASoC: add mclk-fs support to audio graph card .../devicetree/bindings/sound/audio-graph-card.txt | 1 + sound/soc/generic/audio-graph-card.c | 47 ++ 2 files changed, 40 insertions(+), 8 deletions(-) -- 1.9.1
[PATCH 1/2] ASoC: add mclk-fs to audio graph card binding
Add mclk-fs support to audio graph card as initially supported in simple card. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- Documentation/devicetree/bindings/sound/audio-graph-card.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-card.txt index 6e6720a..d04ea3b 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-card.txt +++ b/Documentation/devicetree/bindings/sound/audio-graph-card.txt @@ -17,6 +17,7 @@ Below are same as Simple-Card. - bitclock-master - bitclock-inversion - frame-inversion +- mclk-fs - dai-tdm-slot-num - dai-tdm-slot-width - clocks / system-clock-frequency -- 1.9.1
[PATCH 1/1] ASoC: stm32: sai: fix warning in stm32_sai_set_config()
Fix uninitialized warning introduced by "Move static settings to DAI init" commit in stm32_sai_set_config() function. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 150ad54..08583b9 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -482,13 +482,13 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, cr1_mask = SAI_XCR1_DS_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8); + cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_8); break; case SNDRV_PCM_FORMAT_S16_LE: - cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_16); + cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_16); break; case SNDRV_PCM_FORMAT_S32_LE: - cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_32); + cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_32); break; default: dev_err(cpu_dai->dev, "Data format not supported"); -- 1.9.1
Re: [RFC PATCH 2/2] ASoC: select sysclk clock from mlck clock provider in wm8994 driver
Hello Mark, On 12/20/2017 04:50 PM, Mark Brown wrote: > On Wed, Dec 20, 2017 at 12:42:10PM +0000, Olivier MOYSAN wrote: > >> As a generic machine, simple or audio graph cards are not able to manage >> codec clock muxing. >> If we exclude the management of muxing through codec controls, >> the remaining solution is to handle it fully through clock framework. >> The current patch only supports a limited range of muxing capabilities >> of the codec. >> To have a full management of the muxing, I think it is necessary to add >> a device tree node for each codec interface and to define an aif clock >> in these nodes. >> Then parent clock assignment of these aif clocks would allow to handle >> the muxing. > > Controlling clocking through a clock API binding would be good, yes. > That'd solve a bunch of other problems with use of multi-purpose clocks > for audio as well. > Thanks for your feedback. I will implement this in a patch v2. BRs
Re: [PATCH 0/3] ASoC: stm32: sai: add support of iec958 controls
Hello Takashi, On 04/17/2018 01:17 PM, Mark Brown wrote: > On Tue, Apr 17, 2018 at 08:29:17AM +0000, Olivier MOYSAN wrote: > >> I guess the blocking patch in this patchset is the patch "add IEC958 >> channel status control helper". This patch has been reviewed several >> times, but did not get a ack so far. >> If you think these helpers will not be merged, I will reintegrate the >> corresponding code in stm driver. >> Please let me know, if I need to prepare a v2 without helpers, or if we >> can go further in the review of iec helpers patch ? > > I don't mind either way but you're right here, I'm waiting for Takashi > to review the first patch. I'd probably be OK with it just integrated > into the driver if we have to go that way though. > Kind reminder. Would you have some comments on this patchset ? Thanks olivier
[PATCH v2 0/1] ASoC: stm32: sai: add iec958 controls support
Changes v2: - Remove iec958 helpers and implement iec958 controls in sai driver Olivier Moysan (1): ASoC: stm32: sai: add iec958 controls support sound/soc/stm/Kconfig | 1 + sound/soc/stm/stm32_sai_sub.c | 139 ++ 2 files changed, 128 insertions(+), 12 deletions(-) -- 1.9.1
[PATCH v2 1/1] ASoC: stm32: sai: add iec958 controls support
Add support of iec958 controls for STM32 SAI. Signed-off-by: Olivier Moysan --- sound/soc/stm/Kconfig | 1 + sound/soc/stm/stm32_sai_sub.c | 139 ++ 2 files changed, 128 insertions(+), 12 deletions(-) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 48f9ddd94016..9b2681397dba 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -6,6 +6,7 @@ config SND_SOC_STM32_SAI depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO + select SND_PCM_IEC958 help Say Y if you want to enable SAI for STM32 diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index cfeb219e1d78..c4f15ea14197 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -96,7 +96,8 @@ * @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 - * @spdif_status_bits: S/PDIF status bits + * @snd_aes_iec958: iec958 data + * @ctrl_lock: control lock */ struct stm32_sai_sub_data { struct platform_device *pdev; @@ -125,7 +126,8 @@ struct stm32_sai_sub_data { int slot_mask; int data_size; unsigned int spdif_frm_cnt; - unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES]; + struct snd_aes_iec958 iec958; + struct mutex ctrl_lock; /* protect resources accessed by controls */ }; enum stm32_sai_fifo_th { @@ -184,10 +186,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) } } -static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = { - 0, 0, 0, IEC958_AES3_CON_FS_48000, -}; - static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .reg_bits = 32, .reg_stride = 4, @@ -210,6 +208,49 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) .fast_io = true, }; +static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int snd_pcm_iec958_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uctl) +{ + struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol); + + mutex_lock(>ctrl_lock); + memcpy(uctl->value.iec958.status, sai->iec958.status, 4); + mutex_unlock(>ctrl_lock); + + return 0; +} + +static int snd_pcm_iec958_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uctl) +{ + struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol); + + mutex_lock(>ctrl_lock); + memcpy(sai->iec958.status, uctl->value.iec958.status, 4); + mutex_unlock(>ctrl_lock); + + return 0; +} + +static const struct snd_kcontrol_new iec958_ctls = { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = snd_pcm_iec958_info, + .get = snd_pcm_iec958_get, + .put = snd_pcm_iec958_put, +}; + static irqreturn_t stm32_sai_isr(int irq, void *devid) { struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; @@ -619,6 +660,59 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai) } } +static void stm32_sai_init_iec958_status(struct stm32_sai_sub_data *sai) +{ + unsigned char *cs = sai->iec958.status; + + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; + cs[1] = IEC958_AES1_CON_GENERAL; + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID; +} + +static void stm32_sai_set_iec958_status(struct stm32_sai_sub_data *sai, + struct snd_pcm_runtime *runtime) +{ + if (!runtime) + return; + + /* Force the sample rate according to runtime rate */ + mutex_lock(>ctrl_lock); + switch (runtime->rate) { + case 22050: + sai->iec958.status[3] = IEC958_AES3_CON_FS_22050; + break; + case 44100: + sai->iec958.status[3] = IEC958_AES3_CON_FS_44100; + break; + case 88200: + sai->iec958.status[3] = IEC958_AES3_CON_FS_88200; + break; + case 176400: + sai->iec958.status[3] = IEC958_AES3_CON_FS_176400; + break; + case 24000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_24000; + break; + case 48000:
[INTERNAL][PATCH 1/7] ASoC: stm32: Add synchronization to SAI bindings
Add synchronization configuration to STM32 SAI bindings. This patch also adds peripheral clock which is required to access synchronization register. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 14 +++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index f1c5ae5..1f9cd70 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -10,13 +10,21 @@ Required properties: - reg: Base address and size of SAI common register set. - clocks: Must contain phandle and clock specifier pairs for each entry in clock-names. - - clock-names: Must contain "x8k" and "x11k" + - clock-names: Must contain "pclk" "x8k" and "x11k" + "pclk": Clock which feeds the peripheral bus interface. + Mandatory for "st,stm32h7-sai" compatible. + Not used for "st,stm32f4-sai" compatible. "x8k": SAI parent clock for sampling rates multiple of 8kHz. "x11k": SAI parent clock for sampling rates multiple of 11.025kHz. - interrupts: cpu DAI interrupt line shared by SAI sub-blocks Optional properties: - resets: Reference to a reset controller asserting the SAI + - st,sync: specify synchronization mode. + By default SAI sub-block is in asynchronous mode. + This property sets SAI sub-block as slave of another SAI sub-block. + Must contain the phandle and index of the sai sub-block providing + the synchronization. SAI subnodes: Two subnodes corresponding to SAI sub-block instances A et B can be defined. @@ -52,8 +60,8 @@ sai1: sai1@40015800 { #size-cells = <1>; ranges = <0 0x40015800 0x400>; reg = <0x40015800 0x4>; - clocks = < PLL1_Q>, < PLL2_P>; - clock-names = "x8k", "x11k"; + clocks = < SAI1_CK>, < PLL1_Q>, < PLL2_P>; + clock-names = "pclk", "x8k", "x11k"; interrupts = <87>; sai1a: audio-controller@40015804 { -- 1.9.1
[INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
This patch-set adds support of synchronization features for SAI interface. It also adds minor fixes and improvements. Olivier Moysan (7): ASoC: stm32: Add synchronization to SAI bindings ASoC: stm32: sai: Move static settings to DAI init ASoC: stm32: sai: Fix DMA burst size ASoC: stm32: sai: fix stop management in isr ASoC: stm32: sai: Remove spurious IRQs on stop ASoC: stm32: sai: Fix get reset controller ASoC: stm32: sai: Add synchronization support .../devicetree/bindings/sound/st,stm32-sai.txt | 14 +- sound/soc/stm/stm32_sai.c | 162 - sound/soc/stm/stm32_sai.h | 22 ++- sound/soc/stm/stm32_sai_sub.c | 156 +--- 4 files changed, 318 insertions(+), 36 deletions(-) -- 1.9.1
[INTERNAL][PATCH 2/7] ASoC: stm32: sai: Move static settings to DAI init
Audio interface direction and protocol settings does not change at runtime. So, these settings are moved from hw_params function to dai_probe and set_fmt. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 23 +-- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 90d4396..fdc1891 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -304,12 +304,15 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); - int cr1 = 0, frcr = 0; - int cr1_mask = 0, frcr_mask = 0; + int cr1, frcr = 0; + int cr1_mask, frcr_mask = 0; int ret; dev_dbg(cpu_dai->dev, "fmt %x\n", fmt); + cr1_mask = SAI_XCR1_PRTCFG_MASK; + cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { /* SCK active high for all protocols */ case SND_SOC_DAIFMT_I2S: @@ -336,7 +339,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) return -EINVAL; } - cr1_mask |= SAI_XCR1_PRTCFG_MASK | SAI_XCR1_CKSTR; + cr1_mask |= SAI_XCR1_CKSTR; frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF | SAI_XFRCR_FSDEF; @@ -450,7 +453,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth)); /* Mode, data format and channel config */ - cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); + cr1_mask = SAI_XCR1_DS_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8); @@ -465,11 +468,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, dev_err(cpu_dai->dev, "Data format not supported"); return -EINVAL; } - cr1_mask = SAI_XCR1_DS_MASK | SAI_XCR1_PRTCFG_MASK; - - cr1_mask |= SAI_XCR1_RX_TX; - if (STM_SAI_IS_CAPTURE(sai)) - cr1 |= SAI_XCR1_RX_TX; cr1_mask |= SAI_XCR1_MONO; if ((sai->slots == 2) && (params_channels(params) == 1)) @@ -725,6 +723,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); + int cr1 = 0, cr1_mask; sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX); sai->dma_params.maxburst = 1; @@ -736,7 +735,11 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) else snd_soc_dai_init_dma_data(cpu_dai, NULL, >dma_params); - return 0; + cr1_mask = SAI_XCR1_RX_TX; + if (STM_SAI_IS_CAPTURE(sai)) + cr1 |= SAI_XCR1_RX_TX; + + return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); } static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { -- 1.9.1
[INTERNAL][PATCH 7/7] ASoC: stm32: sai: Add synchronization support
Add Synchronization support for STM32 SAI. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai.c | 160 -- sound/soc/stm/stm32_sai.h | 22 +- sound/soc/stm/stm32_sai_sub.c | 95 + 3 files changed, 269 insertions(+), 8 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 5fe878ac..d6f71a3 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -16,6 +16,7 @@ * details. */ +#include #include #include #include @@ -27,6 +28,16 @@ #include "stm32_sai.h" +static LIST_HEAD(sync_providers); +static DEFINE_MUTEX(sync_mutex); + +struct sync_provider { + struct list_head link; + struct device_node *node; + int (*sync_conf)(void *data, int synco); + void *data; +}; + static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = SAI_STM32F4, }; @@ -41,23 +52,143 @@ {} }; +static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci) +{ + int ret; + + /* Enable peripheral clock to allow GCR register access */ + ret = clk_prepare_enable(sai->pclk); + if (ret) { + dev_err(>pdev->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base); + + clk_disable_unprepare(sai->pclk); + + return 0; +} + +static int stm32_sai_sync_conf_provider(void *data, int synco) +{ + struct stm32_sai_data *sai = (struct stm32_sai_data *)data; + u32 prev_synco; + int ret; + + /* Enable peripheral clock to allow GCR register access */ + ret = clk_prepare_enable(sai->pclk); + if (ret) { + dev_err(>pdev->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + dev_dbg(>pdev->dev, "Set %s%s as synchro provider\n", + sai->pdev->dev.of_node->name, + synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); + + prev_synco = FIELD_GET(SAI_GCR_SYNCOUT_MASK, readl_relaxed(sai->base)); + if (prev_synco != STM_SAI_SYNC_OUT_NONE && synco != prev_synco) { + dev_err(>pdev->dev, "%s%s already set as sync provider\n", + sai->pdev->dev.of_node->name, + prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); + clk_disable_unprepare(sai->pclk); + return -EINVAL; + } + + writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base); + + clk_disable_unprepare(sai->pclk); + + return 0; +} + +static int stm32_sai_set_sync_provider(struct device_node *np, int synco) +{ + struct sync_provider *provider; + int ret; + + mutex_lock(_mutex); + list_for_each_entry(provider, _providers, link) { + if (provider->node == np) { + ret = provider->sync_conf(provider->data, synco); + mutex_unlock(_mutex); + return ret; + } + } + mutex_unlock(_mutex); + + /* SAI sync provider not found */ + return -ENODEV; +} + +static int stm32_sai_set_sync(struct stm32_sai_data *sai, + struct device_node *np_provider, + int synco, int synci) +{ + int ret; + + /* Configure sync client */ + stm32_sai_sync_conf_client(sai, synci); + + /* Configure sync provider */ + ret = stm32_sai_set_sync_provider(np_provider, synco); + + return ret; +} + +static int stm32_sai_sync_add_provider(struct platform_device *pdev, + void *data) +{ + struct sync_provider *sp; + + sp = devm_kzalloc(>dev, sizeof(*sp), GFP_KERNEL); + if (!sp) + return -ENOMEM; + + sp->node = of_node_get(pdev->dev.of_node); + sp->data = data; + sp->sync_conf = _sai_sync_conf_provider; + + mutex_lock(_mutex); + list_add(>link, _providers); + mutex_unlock(_mutex); + + return 0; +} + +static void stm32_sai_sync_del_provider(struct device_node *np) +{ + struct sync_provider *sp; + + mutex_lock(_mutex); + list_for_each_entry(sp, _providers, link) { + if (sp->node == np) { + list_del(>link); + of_node_put(sp->node); + break; + } + } + mutex_unlock(_mutex); +} + static int stm32_sai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct stm32_sai_data *sai; struct reset_control *rst; struct resource *res; -
Re: [INTERNAL][PATCH 0/7] ASoC: stm32: Add SAI synchronization support
Please ignore "[INTERNAL]" in subject. Sorry for this unappropriated header. On 10/19/2017 03:03 PM, Olivier Moysan wrote: > This patch-set adds support of synchronization features for SAI interface. > It also adds minor fixes and improvements. > > Olivier Moysan (7): >ASoC: stm32: Add synchronization to SAI bindings >ASoC: stm32: sai: Move static settings to DAI init >ASoC: stm32: sai: Fix DMA burst size >ASoC: stm32: sai: fix stop management in isr >ASoC: stm32: sai: Remove spurious IRQs on stop >ASoC: stm32: sai: Fix get reset controller >ASoC: stm32: sai: Add synchronization support > > .../devicetree/bindings/sound/st,stm32-sai.txt | 14 +- > sound/soc/stm/stm32_sai.c | 162 > - > sound/soc/stm/stm32_sai.h | 22 ++- > sound/soc/stm/stm32_sai_sub.c | 156 > +--- > 4 files changed, 318 insertions(+), 36 deletions(-) >
[INTERNAL][PATCH 4/7] ASoC: stm32: sai: fix stop management in isr
Add check on substream validity. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 2af397d..815ef10 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -184,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) static irqreturn_t stm32_sai_isr(int irq, void *devid) { struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; - struct snd_pcm_substream *substream = sai->substream; struct platform_device *pdev = sai->pdev; unsigned int sr, imr, flags; snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING; @@ -199,6 +198,11 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); + if (!sai->substream) { + dev_err(>dev, "Device stopped. Spurious IRQ 0x%x\n", sr); + return IRQ_NONE; + } + if (flags & SAI_XIMR_OVRUDRIE) { dev_err(>dev, "IRQ %s\n", STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun"); @@ -227,9 +231,9 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) } if (status != SNDRV_PCM_STATE_RUNNING) { - snd_pcm_stream_lock(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(substream); + snd_pcm_stream_lock(sai->substream); + snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(sai->substream); } return IRQ_HANDLED; -- 1.9.1
[INTERNAL][PATCH 3/7] ASoC: stm32: sai: Fix DMA burst size
Set best burst size tradeoff for 8, 16, 32 bits transfers. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 21 + 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index fdc1891..2af397d 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -445,12 +445,16 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int cr1, cr1_mask, ret; - int fth = STM_SAI_FIFO_TH_HALF; - /* FIFO config */ + /* +* DMA bursts increment is set to 4 words. +* SAI fifo threshold is set to half fifo, to keep enough space +* for DMA incoming bursts. +*/ regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX, SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, - SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth)); + SAI_XCR2_FFLUSH | + SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); /* Mode, data format and channel config */ cr1_mask = SAI_XCR1_DS_MASK; @@ -479,10 +483,6 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, return ret; } - /* DMA config */ - sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32); - snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)>dma_params); - return 0; } @@ -726,7 +726,12 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) int cr1 = 0, cr1_mask; sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX); - sai->dma_params.maxburst = 1; + /* +* DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice, +* as it allows bytes, half-word and words transfers. (See DMA fifos +* constraints). +*/ + sai->dma_params.maxburst = 4; /* Buswidth will be set by framework at runtime */ sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; -- 1.9.1
[INTERNAL][PATCH 5/7] ASoC: stm32: sai: Remove spurious IRQs on stop
Clear IRQ mask on stream stop to avoid spurious IRQs. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai_sub.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 815ef10..fd7dc77 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -419,8 +419,6 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, } /* Enable ITs */ - regmap_update_bits(sai->regmap, STM_SAI_SR_REGX, - SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK); regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); @@ -693,6 +691,9 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n"); + regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, + SAI_XIMR_MASK, 0); + regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_SAIEN, (unsigned int)~SAI_XCR1_SAIEN); -- 1.9.1
[INTERNAL][PATCH 6/7] ASoC: stm32: sai: Fix get reset controller
Use devm version of reset_control_get function to manage driver removing properly. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 1258bef..5fe878ac 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -85,7 +85,7 @@ static int stm32_sai_probe(struct platform_device *pdev) } /* reset */ - rst = reset_control_get_exclusive(>dev, NULL); + rst = devm_reset_control_get_exclusive(>dev, NULL); if (!IS_ERR(rst)) { reset_control_assert(rst); udelay(2); -- 1.9.1
Re: [alsa-devel] [PATCH 1/1] ASoC: stm32: add of dependency for stm32 drivers
hello, On 02/01/2018 10:10 AM, Ladislav Michl wrote: > On Thu, Feb 01, 2018 at 09:54:41AM +0100, Olivier Moysan wrote: >> Add of dependency for STM32 ASoC drivers. >> DFSDM of dependency is already inherited >> from STM32_DFSDM_ADC dependency. >> >> Signed-off-by: olivier moysan <olivier.moy...@st.com> >> --- >> sound/soc/stm/Kconfig | 3 +++ >> 1 file changed, 3 insertions(+) >> >> diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig >> index 3ad881f..b5375f9 100644 >> --- a/sound/soc/stm/Kconfig >> +++ b/sound/soc/stm/Kconfig >> @@ -3,6 +3,7 @@ menu "STMicroelectronics STM32 SOC audio support" >> config SND_SOC_STM32_SAI >> tristate "STM32 SAI interface (Serial Audio Interface) support" >> depends on ARCH_STM32 || COMPILE_TEST >> +depends on OF > > depends on (ARCH_STM32 && OF) || COMPILE_TEST ? > I can find in many configs "depends on OF && (ARCH_X || COMPILE_TEST)" This seems reasonable to me, as the driver always requires OF dependency, regardless the compilation context. In fact, I cannot see why OF would not have to be selected for COMPILE_TEST. BRs >> depends on SND_SOC >> select SND_SOC_GENERIC_DMAENGINE_PCM >> select REGMAP_MMIO >> @@ -12,6 +13,7 @@ config SND_SOC_STM32_SAI >> config SND_SOC_STM32_I2S >> tristate "STM32 I2S interface (SPI/I2S block) support" >> depends on ARCH_STM32 || COMPILE_TEST >> +depends on OF >> depends on SND_SOC >> select SND_SOC_GENERIC_DMAENGINE_PCM >> select REGMAP_MMIO >> @@ -21,6 +23,7 @@ config SND_SOC_STM32_I2S >> config SND_SOC_STM32_SPDIFRX >> tristate "STM32 S/PDIF receiver (SPDIFRX) support" >> depends on ARCH_STM32 || COMPILE_TEST >> +depends on OF >> depends on SND_SOC >> select SND_SOC_GENERIC_DMAENGINE_PCM >> select REGMAP_MMIO >> -- >> 1.9.1 >> >> ___ >> Alsa-devel mailing list >> alsa-de...@alsa-project.org >> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[PATCH 0/2] ASoC: stm32: spdifrx: change dai name
This patchset changes spdifrx dai name and fixes a typo issue. Olivier Moysan (2): ASoC: stm32: spdifrx: fix typo in function name. ASoC: stm32: spdifrx: Use default dai name sound/soc/stm/stm32_spdifrx.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) -- 1.9.1
[PATCH 1/2] ASoC: stm32: spdifrx: fix typo in function name.
Fix function name prefix for naming consistency. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_spdifrx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index b9bdefc..42ad2ae 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -858,8 +858,8 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, {} }; -static int stm_spdifrx_parse_of(struct platform_device *pdev, - struct stm32_spdifrx_data *spdifrx) +static int stm32_spdifrx_parse_of(struct platform_device *pdev, + struct stm32_spdifrx_data *spdifrx) { struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id; @@ -914,7 +914,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, spdifrx); - ret = stm_spdifrx_parse_of(pdev, spdifrx); + ret = stm32_spdifrx_parse_of(pdev, spdifrx); if (ret) return ret; -- 1.9.1
[PATCH 2/2] ASoC: stm32: spdifrx: Use default dai name
Use dai name provided by framework from dev_name() function. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_spdifrx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 42ad2ae..373df4f 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -819,7 +819,6 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { { - .name = "spdifrx-capture-cpu-dai", .probe = stm32_spdifrx_dai_probe, .capture = { .stream_name = "CPU-Capture", -- 1.9.1
[PATCH v2 1/1] ASoC: stm32: add of dependency for stm32 drivers
Add of dependency for STM32 ASoC drivers. DFSDM of dependency is already inherited from STM32_DFSDM_ADC dependency. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 3ad881f..48f9ddd 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -2,7 +2,7 @@ menu "STMicroelectronics STM32 SOC audio support" config SND_SOC_STM32_SAI tristate "STM32 SAI interface (Serial Audio Interface) support" - depends on ARCH_STM32 || COMPILE_TEST + depends on (ARCH_STM32 && OF) || COMPILE_TEST depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO @@ -11,7 +11,7 @@ config SND_SOC_STM32_SAI config SND_SOC_STM32_I2S tristate "STM32 I2S interface (SPI/I2S block) support" - depends on ARCH_STM32 || COMPILE_TEST + depends on (ARCH_STM32 && OF) || COMPILE_TEST depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO @@ -20,7 +20,7 @@ config SND_SOC_STM32_I2S config SND_SOC_STM32_SPDIFRX tristate "STM32 S/PDIF receiver (SPDIFRX) support" - depends on ARCH_STM32 || COMPILE_TEST + depends on (ARCH_STM32 && OF) || COMPILE_TEST depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO -- 1.9.1
[PATCH 1/1] ASoC: stm32: add of dependency for stm32 drivers
Add of dependency for STM32 ASoC drivers. DFSDM of dependency is already inherited from STM32_DFSDM_ADC dependency. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 3ad881f..b5375f9 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -3,6 +3,7 @@ menu "STMicroelectronics STM32 SOC audio support" config SND_SOC_STM32_SAI tristate "STM32 SAI interface (Serial Audio Interface) support" depends on ARCH_STM32 || COMPILE_TEST + depends on OF depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO @@ -12,6 +13,7 @@ config SND_SOC_STM32_SAI config SND_SOC_STM32_I2S tristate "STM32 I2S interface (SPI/I2S block) support" depends on ARCH_STM32 || COMPILE_TEST + depends on OF depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO @@ -21,6 +23,7 @@ config SND_SOC_STM32_I2S config SND_SOC_STM32_SPDIFRX tristate "STM32 S/PDIF receiver (SPDIFRX) support" depends on ARCH_STM32 || COMPILE_TEST + depends on OF depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO -- 1.9.1
[RFC PATCH 1/3] ASoC: stm32: Add S/PDIF to SAI bindings
Add S/PDIF IEC6958 protocol support to STM32 SAI bindings. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 6 ++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index b1acc1a..f301cdf 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -45,6 +45,12 @@ SAI subnodes Optional properties: 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 The device node should contain one 'port' child node with one child 'endpoint' node, according to the bindings defined in Documentation/devicetree/bindings/ -- 1.9.1
[RFC PATCH 3/3] ASoC: stm32: sai: Add support of S/PDIF playback
Add support of S/PDIF iec60958 playback on STM32 SAI. Signed-off-by: olivier moysan <olivier.moy...@st.com> --- sound/soc/stm/stm32_sai.c | 2 + sound/soc/stm/stm32_sai.h | 2 + sound/soc/stm/stm32_sai_sub.c | 153 +++--- 3 files changed, 133 insertions(+), 24 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index d743b7d..f226542 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -30,10 +30,12 @@ static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = SAI_STM32F4, + .has_spdif = false, }; static const struct stm32_sai_conf stm32_sai_conf_h7 = { .version = SAI_STM32H7, + .has_spdif = true, }; static const struct of_device_id stm32_sai_ids[] = { diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index bb062e7..f254221 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -248,9 +248,11 @@ enum stm32_sai_version { /** * struct stm32_sai_conf - SAI configuration * @version: SAI version + * @has_spdif: SAI S/PDIF support flag */ struct stm32_sai_conf { int version; + bool has_spdif; }; /** diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 08583b9..cfeb219 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include "stm32_sai.h" #define SAI_FREE_PROTOCOL 0x0 +#define SAI_SPDIF_PROTOCOL 0x1 #define SAI_SLOT_SIZE_AUTO 0x0 #define SAI_SLOT_SIZE_16 0x1 @@ -59,8 +61,13 @@ #define SAI_SYNC_INTERNAL 0x1 #define SAI_SYNC_EXTERNAL 0x2 +#define STM_SAI_PROTOCOL_IS_SPDIF(ip) ((ip)->spdif) +#define STM_SAI_HAS_SPDIF(x) ((x)->pdata->conf->has_spdif) #define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata)) +#define SAI_IEC60958_BLOCK_FRAMES 192 +#define SAI_IEC60958_STATUS_BYTES 24 + /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) * @pdev: device data pointer @@ -78,6 +85,7 @@ * @id: SAI sub block id corresponding to sub-block A or B * @dir: SAI block direction (playback or capture). set at init * @master: SAI block mode flag. (true=master, false=slave) set at init + * @spdif: SAI S/PDIF iec60958 mode flag. set at init * @fmt: SAI block format. relevant only for custom protocols. set at init * @sync: SAI block synchronization mode. (none, internal or external) * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B) @@ -87,6 +95,8 @@ * @slot_width: rx or tx slot width in bits * @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 + * @spdif_status_bits: S/PDIF status bits */ struct stm32_sai_sub_data { struct platform_device *pdev; @@ -104,6 +114,7 @@ struct stm32_sai_sub_data { unsigned int id; int dir; bool master; + bool spdif; int fmt; int sync; int synco; @@ -113,6 +124,8 @@ struct stm32_sai_sub_data { int slot_width; int slot_mask; int data_size; + unsigned int spdif_frm_cnt; + unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES]; }; enum stm32_sai_fifo_th { @@ -171,6 +184,10 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) } } +static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = { + 0, 0, 0, IEC958_AES3_CON_FS_48000, +}; + static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .reg_bits = 32, .reg_stride = 4, @@ -277,6 +294,11 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int slotr, slotr_mask, slot_size; + if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { + dev_warn(cpu_dai->dev, "Slot setting relevant only for TDM\n"); + return 0; + } + dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n", tx_mask, rx_mask, slots, slot_width); @@ -326,8 +348,17 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) dev_dbg(cpu_dai->dev, "fmt %x\n", fmt); - cr1_mask = SAI_XCR1_PRTCFG_MASK; - cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL); + /* Do not generate master by default */ + cr1 = SAI_XCR1_NODIV; + cr1_mask = SAI_XCR1_NODIV; + + cr1_mask |= SAI_XCR1_PRTCFG_MASK; + if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { + cr1 |= SAI_XCR1_PRTCFG_SET(SAI_SPDIF_PROTOCOL); + goto conf_update; + } + + cr1 |= SAI_XCR1_PRTCFG_SET(
[RFC PATCH 2/3] ASoC: dmaengine_pcm: add processing support
Allow dmaengine client to optionally register a processing callback. This callback is intended to apply processing on samples in buffer copied from/to user space, before/after DMA transfer. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- include/sound/dmaengine_pcm.h | 3 ++ sound/soc/soc-generic-dmaengine-pcm.c | 62 +-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 8a5a840..47ef486 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -140,6 +140,9 @@ struct snd_dmaengine_pcm_config { struct dma_chan *(*compat_request_channel)( struct snd_soc_pcm_runtime *rtd, struct snd_pcm_substream *substream); + int (*process)(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes); dma_filter_fn compat_filter_fn; struct device *dma_dev; const char *chan_names[SNDRV_PCM_STREAM_LAST + 1]; diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index c07d5c7..1c1d838 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -340,6 +340,41 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer( return snd_dmaengine_pcm_pointer(substream); } +static int dmaengine_copy_user(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME); + struct snd_pcm_runtime *runtime = substream->runtime; + struct dmaengine_pcm *pcm = soc_component_to_pcm(component); + int (*process)(struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void *buf, unsigned long bytes) = pcm->config->process; + bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + void *dma_ptr = runtime->dma_area + hwoff + + channel * (runtime->dma_bytes / runtime->channels); + int ret; + + if (is_playback) + if (copy_from_user(dma_ptr, (void __user *)buf, bytes)) + return -EFAULT; + + if (process) { + ret = process(substream, channel, hwoff, + (void __user *)buf, bytes); + if (ret < 0) + return ret; + } + + if (!is_playback) + if (copy_to_user((void __user *)buf, dma_ptr, bytes)) + return -EFAULT; + + return 0; +} + static const struct snd_pcm_ops dmaengine_pcm_ops = { .open = dmaengine_pcm_open, .close = snd_dmaengine_pcm_close, @@ -350,6 +385,17 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer( .pointer= dmaengine_pcm_pointer, }; +static const struct snd_pcm_ops dmaengine_pcm_process_ops = { + .open = dmaengine_pcm_open, + .close = snd_dmaengine_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = dmaengine_pcm_hw_params, + .hw_free= snd_pcm_lib_free_pages, + .trigger= snd_dmaengine_pcm_trigger, + .pointer= dmaengine_pcm_pointer, + .copy_user = dmaengine_copy_user, +}; + static const struct snd_soc_component_driver dmaengine_pcm_component = { .name = SND_DMAENGINE_PCM_DRV_NAME, .probe_order= SND_SOC_COMP_ORDER_LATE, @@ -357,6 +403,13 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer( .pcm_new= dmaengine_pcm_new, }; +static const struct snd_soc_component_driver dmaengine_pcm_component_process = { + .name = SND_DMAENGINE_PCM_DRV_NAME, + .probe_order= SND_SOC_COMP_ORDER_LATE, + .ops= _pcm_process_ops, + .pcm_new= dmaengine_pcm_new, +}; + static const char * const dmaengine_pcm_dma_channel_names[] = { [SNDRV_PCM_STREAM_PLAYBACK] = "tx", [SNDRV_PCM_STREAM_CAPTURE] = "rx", @@ -449,8 +502,13 @@ int snd_dmaengine_pcm_register(struct device *dev, if (ret) goto err_free_dma; - ret = snd_soc_add_component(dev, >component, - _pcm_component, NULL, 0); + if (config && config->process) + ret = snd_soc_add_component(dev, >component, + _pcm_component_process, + NULL, 0); + else + ret = snd_soc_add_component(dev,
[RFC PATCH 0/3] ASoC: stm32: add S/PDIF support to SAI
This patch-set adds S/PDIF IEC6958 protocol support to STM32 SAI. Only S/PDIF playback is supported here, as SAI peripheral does not support S/PDIF capture. SAI peripheral does not take as input full IEC60958 frames as it generates preamble and parity bit. However, it cannot handle raw PCM data, as it is not designed to insert channel status and user data in the generated IEC frames. Moreover, SAI data register format does not match exactly IEC60958 subframe format. (see figure below). Channel status (C) and User data (U) are at 26-25 bits position, in data register, instead of 30-29 bits position. IEC60958 subframe bits: 31-28 27-4 3-0 PCUVdata (16|24 bits)preamble SAI data register format: 27-2423-0 P CUVdata (16|24 bits) The impact in software is that the data have to be processed before DMA transfer. These constraints should be managed at driver level to minimize the impact on application. This means that a callback is necessary to perform data processing (shift and channel status insertion) This patch-set introduces a callback to allow processing on samples. The implementation is based on previous discussions available here: https://patchwork.kernel.org/patch/9570255/ BRs Olivier Olivier Moysan (3): ASoC: stm32: Add S/PDIF to SAI bindings ASoC: dmaengine_pcm: add processing support ASoC: stm32: sai: Add support of S/PDIF playback .../devicetree/bindings/sound/st,stm32-sai.txt | 6 + include/sound/dmaengine_pcm.h | 3 + sound/soc/soc-generic-dmaengine-pcm.c | 62 - sound/soc/stm/stm32_sai.c | 2 + sound/soc/stm/stm32_sai.h | 2 + sound/soc/stm/stm32_sai_sub.c | 153 + 6 files changed, 202 insertions(+), 26 deletions(-) -- 1.9.1
[PATCH 0/3] ASoC: stm32: sai: add support of iec958 controls
This patchset adds support of iec958 controls to STM32 SAI driver. The patch makes use of iec958 control status helpers previously proposed and discussed through the following threads: https://patchwork.kernel.org/patch/8062601/ https://patchwork.kernel.org/patch/8091551/ (v2) https://patchwork.kernel.org/patch/8462961/ (v3) https://patchwork.kernel.org/patch/8533731/ (v4) Olivier Moysan (3): ALSA: pcm: add IEC958 channel status control helper ASoC: stm32: sai: add iec958 controls support ASoC: dmaengine_pcm: document process callback include/sound/dmaengine_pcm.h | 2 + include/sound/pcm_iec958.h| 19 +++ sound/core/pcm_iec958.c | 114 ++ sound/soc/stm/Kconfig | 1 + sound/soc/stm/stm32_sai_sub.c | 101 - 5 files changed, 225 insertions(+), 12 deletions(-) -- 1.9.1
[PATCH 2/3] ASoC: stm32: sai: add iec958 controls support
Add support of iec958 controls for STM32 SAI. Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- sound/core/pcm_iec958.c | 1 + sound/soc/stm/Kconfig | 1 + sound/soc/stm/stm32_sai_sub.c | 101 +- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index aba1f522e98a..c34735ac3c48 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -19,6 +19,7 @@ static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; + return 0; } diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 48f9ddd94016..9b2681397dba 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -6,6 +6,7 @@ config SND_SOC_STM32_SAI depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO + select SND_PCM_IEC958 help Say Y if you want to enable SAI for STM32 diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index cfeb219e1d78..c2e487e133aa 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "stm32_sai.h" @@ -96,7 +97,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 - * @spdif_status_bits: S/PDIF status bits + * @snd_aes_iec958: iec958 data */ struct stm32_sai_sub_data { struct platform_device *pdev; @@ -125,7 +126,7 @@ struct stm32_sai_sub_data { int slot_mask; int data_size; unsigned int spdif_frm_cnt; - unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES]; + struct snd_aes_iec958 iec958; }; enum stm32_sai_fifo_th { @@ -184,10 +185,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) } } -static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = { - 0, 0, 0, IEC958_AES3_CON_FS_48000, -}; - static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .reg_bits = 32, .reg_stride = 4, @@ -619,6 +616,59 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai) } } +static void stm32_sai_set_channel_status(struct stm32_sai_sub_data *sai, +struct snd_pcm_runtime *runtime) +{ + if (!runtime) + return; + + /* Force the sample rate according to runtime rate */ + switch (runtime->rate) { + case 22050: + sai->iec958.status[3] = IEC958_AES3_CON_FS_22050; + break; + case 44100: + sai->iec958.status[3] = IEC958_AES3_CON_FS_44100; + break; + case 88200: + sai->iec958.status[3] = IEC958_AES3_CON_FS_88200; + break; + case 176400: + sai->iec958.status[3] = IEC958_AES3_CON_FS_176400; + break; + case 24000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_24000; + break; + case 48000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_48000; + break; + case 96000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_96000; + break; + case 192000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_192000; + break; + case 32000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_32000; + break; + default: + sai->iec958.status[3] = IEC958_AES3_CON_FS_NOTID; + break; + } +} + +static int stm32_sai_iec958_set(struct snd_pcm_iec958_params *iec_param) +{ + struct stm32_sai_sub_data *sai = iec_param->private_data; + + if (!sai->substream) + return 0; + + stm32_sai_set_channel_status(sai, sai->substream->runtime); + + return 0; +} + static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, struct snd_pcm_hw_params *params) { @@ -709,7 +759,11 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream, sai->data_size = params_width(params); - if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) { + if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { + /* Rate not already set in runtime structure */ + substream->runtime->rate = params_rate(params); + stm32_sai_set_channel_status(sai, substream->runtime); + } else { ret = stm32_sai_set_slots(cpu_dai); if (ret < 0) return ret; @@ -789,6 +843,28 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *s
[PATCH 1/3] ALSA: pcm: add IEC958 channel status control helper
From: Arnaud Pouliquen <arnaud.pouliq...@st.com> Add IEC958 channel status helper that creates control to handle the IEC60958 status bits. Signed-off-by: Arnaud Pouliquen <arnaud.pouliq...@st.com> Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- include/sound/pcm_iec958.h | 19 sound/core/pcm_iec958.c| 113 + 2 files changed, 132 insertions(+) diff --git a/include/sound/pcm_iec958.h b/include/sound/pcm_iec958.h index 0939aa45e2fe..3c9701a9b1b0 100644 --- a/include/sound/pcm_iec958.h +++ b/include/sound/pcm_iec958.h @@ -4,9 +4,28 @@ #include +/** + * struct snd_pcm_iec958_params: IEC 60958 controls parameters + * @ctrl_set: control set callback + * This callback is optional and shall be used to set associated driver + * configuration. + * @iec: Mandatory pointer to iec958 structure. + * @cs: Mandatory pointer to AES/IEC958 channel status bits. + * @cs_len: size in byte of the AES/IEC958 channel status bits. + * @private_data: Optional private pointer to driver context. + */ +struct snd_pcm_iec958_params { + int (*ctrl_set)(struct snd_pcm_iec958_params *iec_param); + unsigned char *cs; + unsigned char cs_len; + void *private_data; +}; + int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, size_t len); int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, u8 *cs, size_t len); +int snd_pcm_add_iec958_ctl(struct snd_pcm *pcm, int subdevice, int stream, + struct snd_pcm_iec958_params *params); #endif diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index 5e6aed64f451..aba1f522e98a 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -7,11 +7,88 @@ */ #include #include +#include #include +#include #include #include #include +static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +/* + * IEC958 channel status default controls callbacks + */ +static int snd_pcm_iec958_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uctl) +{ + struct snd_pcm_iec958_params *params = snd_kcontrol_chip(kcontrol); + int i; + + for (i = 0; i < params->cs_len; i++) + uctl->value.iec958.status[i] = params->cs[i]; + + return 0; +} + +static int snd_pcm_iec958_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uctl) +{ + struct snd_pcm_iec958_params *params = snd_kcontrol_chip(kcontrol); + int err = 0; + unsigned int i, updated = 0; + unsigned char old_status[5]; + + for (i = 0; i < params->cs_len; i++) { + if (params->cs[i] != uctl->value.iec958.status[i]) + updated = 1; + } + + if (!updated) + return 0; + + /* Store current status to restore them in error case */ + for (i = 0; i < params->cs_len; i++) { + old_status[i] = params->cs[i]; + params->cs[i] = uctl->value.iec958.status[i]; + } + + if (params->ctrl_set) + err = params->ctrl_set(params); + if (err < 0) { + for (i = 0; i < params->cs_len; i++) + params->cs[i] = old_status[i]; + } + + return err; +} + +static const struct snd_kcontrol_new iec958_ctls[] = { + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = snd_pcm_iec958_info, + .get = snd_pcm_iec958_get, + .put = snd_pcm_iec958_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .info = snd_pcm_iec958_info, + .get = snd_pcm_iec958_get, + }, +}; + static int create_iec958_consumer(uint rate, uint sample_width, u8 *cs, size_t len) { @@ -21,6 +98,9 @@ static int create_iec958_consumer(uint rate, uint sample_width, return -EINVAL; switch (rate) { + case 0: + fs = IEC958_AES3_CON_FS_NOTID; + break; case 32000: fs = IEC958_AES3_CON_FS_32000; break; @@ -48,6 +128,9 @@ static int create_iec958_consumer(uint rate, uint
[PATCH 3/3] ASoC: dmaengine_pcm: document process callback
Add missing description of process callback. Fixes: 78648092ef46 ("ASoC: dmaengine_pcm: add processing support") Signed-off-by: Olivier Moysan <olivier.moy...@st.com> --- include/sound/dmaengine_pcm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 47ef486852ed..e3481eebdd98 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -118,6 +118,8 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * PCM substream. Will be called from the PCM drivers hwparams callback. * @compat_request_channel: Callback to request a DMA channel for platforms * which do not use devicetree. + * @process: Callback used to apply processing on samples transferred from/to + * user space. * @compat_filter_fn: Will be used as the filter function when requesting a * channel for platforms which do not use devicetree. The filter parameter * will be the DAI's DMA data. -- 1.9.1
Re: [PATCH 0/3] ASoC: stm32: sai: add support of iec958 controls
Hello, I guess the blocking patch in this patchset is the patch "add IEC958 channel status control helper". This patch has been reviewed several times, but did not get a ack so far. If you think these helpers will not be merged, I will reintegrate the corresponding code in stm driver. Please let me know, if I need to prepare a v2 without helpers, or if we can go further in the review of iec helpers patch ? Best regards olivier On 03/13/2018 05:27 PM, Olivier Moysan wrote: > This patchset adds support of iec958 controls to STM32 SAI driver. > > The patch makes use of iec958 control status helpers previously proposed > and discussed through the following threads: > https://patchwork.kernel.org/patch/8062601/ > https://patchwork.kernel.org/patch/8091551/ (v2) > https://patchwork.kernel.org/patch/8462961/ (v3) > https://patchwork.kernel.org/patch/8533731/ (v4) > > Olivier Moysan (3): >ALSA: pcm: add IEC958 channel status control helper >ASoC: stm32: sai: add iec958 controls support >ASoC: dmaengine_pcm: document process callback > > include/sound/dmaengine_pcm.h | 2 + > include/sound/pcm_iec958.h| 19 +++ > sound/core/pcm_iec958.c | 114 > ++ > sound/soc/stm/Kconfig | 1 + > sound/soc/stm/stm32_sai_sub.c | 101 - > 5 files changed, 225 insertions(+), 12 deletions(-) >
[PATCH 2/4] ASoC: dt-bindings: add mclk support to cs42l51
Add clocks properties to cs42l51 Cirrus codec, to support master clock provider. Signed-off-by: Olivier Moysan --- Documentation/devicetree/bindings/sound/cs42l51.txt | 17 + Documentation/devicetree/bindings/trivial-devices.txt | 1 - 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/cs42l51.txt diff --git a/Documentation/devicetree/bindings/sound/cs42l51.txt b/Documentation/devicetree/bindings/sound/cs42l51.txt new file mode 100644 index ..4b5de33ce377 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs42l51.txt @@ -0,0 +1,17 @@ +CS42L51 audio CODEC + +Optional properties: + + - clocks : a list of phandles + clock-specifiers, one for each entry in +clock-names + + - clock-names : must contain "MCLK" + +Example: + +cs42l51: cs42l51@4a { + compatible = "cirrus,cs42l51"; + reg = <0x4a>; + clocks = <_prov>; + clock-names = "MCLK"; +}; diff --git a/Documentation/devicetree/bindings/trivial-devices.txt b/Documentation/devicetree/bindings/trivial-devices.txt index 763a2808a95c..69c934aec13b 100644 --- a/Documentation/devicetree/bindings/trivial-devices.txt +++ b/Documentation/devicetree/bindings/trivial-devices.txt @@ -35,7 +35,6 @@ at,24c08 i2c serial eeprom (24cxx) atmel,at97sc3204t i2c trusted platform module (TPM) capella,cm32181CM32181: Ambient Light Sensor capella,cm3232 CM3232: Ambient Light Sensor -cirrus,cs42l51 Cirrus Logic CS42L51 audio codec dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output dallas,ds1631 High-Precision Digital Thermometer dallas,ds1672 Dallas DS1672 Real-time Clock -- 2.7.4
[PATCH 1/4] ASoC: dt-bindings: add mclk provider support to stm32 sai
add mclk provider support to stm32 sai Signed-off-by: Olivier Moysan --- Documentation/devicetree/bindings/sound/st,stm32-sai.txt | 7 +++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt index 3a3fc506e43a..3f4467ff0aa2 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt @@ -31,7 +31,11 @@ SAI subnodes required properties: - 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/stm32-dma.txt - dma-names: identifier string for each DMA request line "tx": if sai sub-block is configured as playback DAI @@ -51,6 +55,9 @@ SAI subnodes Optional properties: 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/ -- 2.7.4
[PATCH 3/4] ASoC: stm32: sai: set sai as mclk clock provider
Add master clock generation support in STM32 SAI. The master clock provided by SAI can be used to feed a codec. Signed-off-by: Olivier Moysan --- sound/soc/stm/stm32_sai.h | 3 + sound/soc/stm/stm32_sai_sub.c | 275 -- 2 files changed, 242 insertions(+), 36 deletions(-) diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index f25422174909..08de899c766b 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -91,6 +91,9 @@ #define SAI_XCR1_OSR_SHIFT 26 #define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT) +#define SAI_XCR1_MCKEN_SHIFT 27 +#define SAI_XCR1_MCKEN BIT(SAI_XCR1_MCKEN_SHIFT) + /*** Bit definition for SAI_XCR2 register ***/ #define SAI_XCR2_FTH_SHIFT 0 #define SAI_XCR2_FTH_MASK GENMASK(2, SAI_XCR2_FTH_SHIFT) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 56a227e0bd71..31d22abd3204 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -68,6 +69,8 @@ #define SAI_IEC60958_BLOCK_FRAMES 192 #define SAI_IEC60958_STATUS_BYTES 24 +#define SAI_MCLK_NAME_LEN 32 + /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) * @pdev: device data pointer @@ -80,6 +83,7 @@ * @pdata: SAI block parent data pointer * @np_sync_provider: synchronization provider node * @sai_ck: kernel clock feeding the SAI clock generator + * @sai_mclk: master clock from SAI mclk provider * @phys_addr: SAI registers physical base address * @mclk_rate: SAI block master clock frequency (Hz). set at init * @id: SAI sub block id corresponding to sub-block A or B @@ -110,6 +114,7 @@ struct stm32_sai_sub_data { struct stm32_sai_data *pdata; struct device_node *np_sync_provider; struct clk *sai_ck; + struct clk *sai_mclk; dma_addr_t phys_addr; unsigned int mclk_rate; unsigned int id; @@ -251,6 +256,177 @@ static const struct snd_kcontrol_new iec958_ctls = { .put = snd_pcm_iec958_put, }; +struct stm32_sai_mclk_data { + struct clk_hw hw; + unsigned long freq; + struct stm32_sai_sub_data *sai_data; +}; + +#define to_mclk_data(_hw) container_of(_hw, struct stm32_sai_mclk_data, hw) +#define STM32_SAI_MAX_CLKS 1 + +static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai, +unsigned long input_rate, +unsigned long output_rate) +{ + int version = sai->pdata->conf->version; + int div; + + div = DIV_ROUND_CLOSEST(input_rate, output_rate); + if (div > SAI_XCR1_MCKDIV_MAX(version)) { + dev_err(>pdev->dev, "Divider %d out of range\n", div); + return -EINVAL; + } + dev_dbg(>pdev->dev, "SAI divider %d\n", div); + + if (input_rate % div) + dev_dbg(>pdev->dev, + "Rate not accurate. requested (%ld), actual (%ld)\n", + output_rate, input_rate / div); + + return div; +} + +static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai, +unsigned int div) +{ + int version = sai->pdata->conf->version; + int ret, cr1, mask; + + if (div > SAI_XCR1_MCKDIV_MAX(version)) { + dev_err(>pdev->dev, "Divider %d out of range\n", div); + return -EINVAL; + } + + mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); + cr1 = SAI_XCR1_MCKDIV_SET(div); + ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); + if (ret < 0) + dev_err(>pdev->dev, "Failed to update CR1 register\n"); + + return ret; +} + +static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + struct stm32_sai_sub_data *sai = mclk->sai_data; + int div; + + div = stm32_sai_get_clk_div(sai, *prate, rate); + if (div < 0) + return div; + + mclk->freq = *prate / div; + + return mclk->freq; +} + +static unsigned long stm32_sai_mclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + + return mclk->freq; +} + +static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct stm32_sai_mclk_data *mclk = to_mclk_data(hw); + struct stm32_sai_sub_data *sai = mclk->sai_data; + unsigned int div; + int re
[PATCH 0/4] ASoC: stm32: sai: add mclk clock provider
This patch set allows to use STM32 SAI interface as a master clock provider. The Cirrus cs42l51 codec patch gives the example of the source code required on codec side, to use SAI mclk provider. These patches allow to cover the following use cases: - SAI is master or slave and is master clock provider - SAI is master or slave and is not master clock provider (another sai provides the mclk clock) Implementation overview: - mclk configuration SAI is registered in clock framework: - either as a mclk provider (optional in DT). SAI generates mclk when requested by DAPM - or as a mclk consumer (optional in DT). cs42l51 codec is configured as a mclk consumer (optional in DT) - mclk power A DAPM is registered in codec to handle mclk enable/disable (DAPM route is set in soundcard node) - mclk rate: mclk rate is computed at runtime from stream rate and mclk-fs ratio provided in DT mclk rate is propagated through sysclk callback to the SAI which is mclk consumer. The mclk rate is set exclusively to avoid concurrent rate requests on SAI master. Regards Olivier Olivier Moysan (4): ASoC: dt-bindings: add mclk provider support to stm32 sai ASoC: dt-bindings: add mclk support to cs42l51 ASoC: stm32: sai: set sai as mclk clock provider ASoC: cs42l51: add mclk support .../devicetree/bindings/sound/cs42l51.txt | 17 ++ .../devicetree/bindings/sound/st,stm32-sai.txt | 7 + .../devicetree/bindings/trivial-devices.txt| 1 - sound/soc/codecs/cs42l51.c | 8 + sound/soc/stm/stm32_sai.h | 3 + sound/soc/stm/stm32_sai_sub.c | 275 ++--- 6 files changed, 274 insertions(+), 37 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/cs42l51.txt -- 2.7.4
[PATCH 4/4] ASoC: cs42l51: add mclk support
Add MCLK dapm to allow configuration of cirrus CS42l51 codec as a master clock consumer. 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 5080d7a3c279..eb40bff54cec 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -237,6 +237,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { _adcr_mux_controls), }; +static const struct snd_soc_dapm_widget cs42l51_dapm_mclk_widgets[] = { + SND_SOC_DAPM_CLOCK_SUPPLY("MCLK") +}; + static const struct snd_soc_dapm_route cs42l51_routes[] = { {"HPL", NULL, "Left DAC"}, {"HPR", NULL, "Right DAC"}, @@ -487,6 +491,10 @@ static struct snd_soc_dai_driver cs42l51_dai = { static int cs42l51_component_probe(struct snd_soc_component *component) { int ret, reg; + struct snd_soc_dapm_context *dapm; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1); /* * DAC configuration -- 2.7.4
[PATCH 1/2] ASoC: stm32: add clock dependency for sai
Fixes: 8307b2afd386 ("ASoC: stm32: sai: set sai as mclk clock provider") Add COMMON_CLK dependency for STM32 SAI, as it is required by clock provider. Signed-off-by: Olivier Moysan --- sound/soc/stm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 9b2681397dba..c66ffa72057e 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -3,6 +3,7 @@ menu "STMicroelectronics STM32 SOC audio support" config SND_SOC_STM32_SAI tristate "STM32 SAI interface (Serial Audio Interface) support" depends on (ARCH_STM32 && OF) || COMPILE_TEST + depends on COMMON_CLK depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO -- 2.7.4
[PATCH 0/2] ASoC: stm32: sai: fix kbuild errors
These patches fix following compilation errors: - >> sound/soc/stm/stm32_sai_sub.c:260:16: error: field 'hw' has incomplete type - >> sound/soc/stm/stm32_sai_sub.c:412:3: warning: 'strncat' specified bound 6 equals source length [-Wstringop-overflow=] Olivier Moysan (2): ASoC: stm32: add clock dependency for sai ASoC: stm32: sai: fix master clock naming sound/soc/stm/Kconfig | 1 + sound/soc/stm/stm32_sai_sub.c | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) -- 2.7.4
[PATCH 2/2] ASoC: stm32: sai: fix master clock naming
Fixes: 8307b2afd386 ("ASoC: stm32: sai: set sai as mclk clock provider") Fix warning issued by strncat when bound equals to source length. Signed-off-by: Olivier Moysan --- sound/soc/stm/stm32_sai_sub.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 31d22abd3204..ea05cc91aa05 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -404,12 +404,11 @@ static int stm32_sai_add_mclk_provider(struct stm32_sai_sub_data *sai) * String after "_" char is stripped in parent name. */ p = mclk_name; - while (*s && *s != '_' && (i < (SAI_MCLK_NAME_LEN - 6))) { + while (*s && *s != '_' && (i < (SAI_MCLK_NAME_LEN - 7))) { *p++ = *s++; i++; } - STM_SAI_IS_SUB_A(sai) ? - strncat(p, "a_mclk", 6) : strncat(p, "b_mclk", 6); + STM_SAI_IS_SUB_A(sai) ? strcat(p, "a_mclk") : strcat(p, "b_mclk"); mclk->hw.init = CLK_HW_INIT(mclk_name, pname, _ops, 0); mclk->sai_data = sai; -- 2.7.4
[PATCH 1/1] ASoC: cs42l51: fix mclk support
Fixes: 5e8d63a726f8 ("ASoC: cs42l51: add mclk support") The MCLK clock is made optional for cs42l51 codec. However, ASoC DAPM clock supply widget, expects the clock to be defined unconditionally. Register MCLK DAPM conditionally in codec driver, depending on clock presence in DT. Signed-off-by: Olivier Moysan --- sound/soc/codecs/cs42l51.c | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index eb40bff54cec..fd2bd74024c1 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -21,6 +21,7 @@ * - master mode *NOT* supported */ +#include #include #include #include @@ -41,6 +42,7 @@ enum master_slave_mode { 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; }; @@ -492,9 +494,13 @@ static int cs42l51_component_probe(struct snd_soc_component *component) { int ret, reg; struct snd_soc_dapm_context *dapm; + struct cs42l51_private *cs42l51; + cs42l51 = snd_soc_component_get_drvdata(component); dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1); + + if (cs42l51->mclk_handle) + snd_soc_dapm_new_controls(dapm, cs42l51_dapm_mclk_widgets, 1); /* * DAC configuration @@ -548,6 +554,13 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) dev_set_drvdata(dev, cs42l51); + cs42l51->mclk_handle = devm_clk_get(dev, "MCLK"); + if (IS_ERR(cs42l51->mclk_handle)) { + if (PTR_ERR(cs42l51->mclk_handle) != -ENOENT) + return PTR_ERR(cs42l51->mclk_handle); + cs42l51->mclk_handle = NULL; + } + /* Verify that we have a CS42L51 */ ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, ); if (ret < 0) { -- 2.7.4
[PATCH 0/3] ASoC: stm32: sai: add support of iec958 controls
This patchset adds support of iec958 controls to STM32 SAI driver. The patch makes use of iec958 control status helpers previously proposed and discussed through the following threads: https://patchwork.kernel.org/patch/8062601/ https://patchwork.kernel.org/patch/8091551/ (v2) https://patchwork.kernel.org/patch/8462961/ (v3) https://patchwork.kernel.org/patch/8533731/ (v4) Olivier Moysan (3): ALSA: pcm: add IEC958 channel status control helper ASoC: stm32: sai: add iec958 controls support ASoC: dmaengine_pcm: document process callback include/sound/dmaengine_pcm.h | 2 + include/sound/pcm_iec958.h| 19 +++ sound/core/pcm_iec958.c | 114 ++ sound/soc/stm/Kconfig | 1 + sound/soc/stm/stm32_sai_sub.c | 101 - 5 files changed, 225 insertions(+), 12 deletions(-) -- 1.9.1
[PATCH 2/3] ASoC: stm32: sai: add iec958 controls support
Add support of iec958 controls for STM32 SAI. Signed-off-by: Olivier Moysan --- sound/core/pcm_iec958.c | 1 + sound/soc/stm/Kconfig | 1 + sound/soc/stm/stm32_sai_sub.c | 101 +- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index aba1f522e98a..c34735ac3c48 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -19,6 +19,7 @@ static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; + return 0; } diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig index 48f9ddd94016..9b2681397dba 100644 --- a/sound/soc/stm/Kconfig +++ b/sound/soc/stm/Kconfig @@ -6,6 +6,7 @@ config SND_SOC_STM32_SAI depends on SND_SOC select SND_SOC_GENERIC_DMAENGINE_PCM select REGMAP_MMIO + select SND_PCM_IEC958 help Say Y if you want to enable SAI for STM32 diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index cfeb219e1d78..c2e487e133aa 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "stm32_sai.h" @@ -96,7 +97,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 - * @spdif_status_bits: S/PDIF status bits + * @snd_aes_iec958: iec958 data */ struct stm32_sai_sub_data { struct platform_device *pdev; @@ -125,7 +126,7 @@ struct stm32_sai_sub_data { int slot_mask; int data_size; unsigned int spdif_frm_cnt; - unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES]; + struct snd_aes_iec958 iec958; }; enum stm32_sai_fifo_th { @@ -184,10 +185,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) } } -static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = { - 0, 0, 0, IEC958_AES3_CON_FS_48000, -}; - static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .reg_bits = 32, .reg_stride = 4, @@ -619,6 +616,59 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai) } } +static void stm32_sai_set_channel_status(struct stm32_sai_sub_data *sai, +struct snd_pcm_runtime *runtime) +{ + if (!runtime) + return; + + /* Force the sample rate according to runtime rate */ + switch (runtime->rate) { + case 22050: + sai->iec958.status[3] = IEC958_AES3_CON_FS_22050; + break; + case 44100: + sai->iec958.status[3] = IEC958_AES3_CON_FS_44100; + break; + case 88200: + sai->iec958.status[3] = IEC958_AES3_CON_FS_88200; + break; + case 176400: + sai->iec958.status[3] = IEC958_AES3_CON_FS_176400; + break; + case 24000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_24000; + break; + case 48000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_48000; + break; + case 96000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_96000; + break; + case 192000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_192000; + break; + case 32000: + sai->iec958.status[3] = IEC958_AES3_CON_FS_32000; + break; + default: + sai->iec958.status[3] = IEC958_AES3_CON_FS_NOTID; + break; + } +} + +static int stm32_sai_iec958_set(struct snd_pcm_iec958_params *iec_param) +{ + struct stm32_sai_sub_data *sai = iec_param->private_data; + + if (!sai->substream) + return 0; + + stm32_sai_set_channel_status(sai, sai->substream->runtime); + + return 0; +} + static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, struct snd_pcm_hw_params *params) { @@ -709,7 +759,11 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream, sai->data_size = params_width(params); - if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) { + if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { + /* Rate not already set in runtime structure */ + substream->runtime->rate = params_rate(params); + stm32_sai_set_channel_status(sai, substream->runtime); + } else { ret = stm32_sai_set_slots(cpu_dai); if (ret < 0) return ret; @@ -789,6 +843,28 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, sai->subst
[PATCH 1/3] ALSA: pcm: add IEC958 channel status control helper
From: Arnaud Pouliquen Add IEC958 channel status helper that creates control to handle the IEC60958 status bits. Signed-off-by: Arnaud Pouliquen Signed-off-by: Olivier Moysan --- include/sound/pcm_iec958.h | 19 sound/core/pcm_iec958.c| 113 + 2 files changed, 132 insertions(+) diff --git a/include/sound/pcm_iec958.h b/include/sound/pcm_iec958.h index 0939aa45e2fe..3c9701a9b1b0 100644 --- a/include/sound/pcm_iec958.h +++ b/include/sound/pcm_iec958.h @@ -4,9 +4,28 @@ #include +/** + * struct snd_pcm_iec958_params: IEC 60958 controls parameters + * @ctrl_set: control set callback + * This callback is optional and shall be used to set associated driver + * configuration. + * @iec: Mandatory pointer to iec958 structure. + * @cs: Mandatory pointer to AES/IEC958 channel status bits. + * @cs_len: size in byte of the AES/IEC958 channel status bits. + * @private_data: Optional private pointer to driver context. + */ +struct snd_pcm_iec958_params { + int (*ctrl_set)(struct snd_pcm_iec958_params *iec_param); + unsigned char *cs; + unsigned char cs_len; + void *private_data; +}; + int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, size_t len); int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, u8 *cs, size_t len); +int snd_pcm_add_iec958_ctl(struct snd_pcm *pcm, int subdevice, int stream, + struct snd_pcm_iec958_params *params); #endif diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index 5e6aed64f451..aba1f522e98a 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -7,11 +7,88 @@ */ #include #include +#include #include +#include #include #include #include +static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +/* + * IEC958 channel status default controls callbacks + */ +static int snd_pcm_iec958_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uctl) +{ + struct snd_pcm_iec958_params *params = snd_kcontrol_chip(kcontrol); + int i; + + for (i = 0; i < params->cs_len; i++) + uctl->value.iec958.status[i] = params->cs[i]; + + return 0; +} + +static int snd_pcm_iec958_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uctl) +{ + struct snd_pcm_iec958_params *params = snd_kcontrol_chip(kcontrol); + int err = 0; + unsigned int i, updated = 0; + unsigned char old_status[5]; + + for (i = 0; i < params->cs_len; i++) { + if (params->cs[i] != uctl->value.iec958.status[i]) + updated = 1; + } + + if (!updated) + return 0; + + /* Store current status to restore them in error case */ + for (i = 0; i < params->cs_len; i++) { + old_status[i] = params->cs[i]; + params->cs[i] = uctl->value.iec958.status[i]; + } + + if (params->ctrl_set) + err = params->ctrl_set(params); + if (err < 0) { + for (i = 0; i < params->cs_len; i++) + params->cs[i] = old_status[i]; + } + + return err; +} + +static const struct snd_kcontrol_new iec958_ctls[] = { + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = snd_pcm_iec958_info, + .get = snd_pcm_iec958_get, + .put = snd_pcm_iec958_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .info = snd_pcm_iec958_info, + .get = snd_pcm_iec958_get, + }, +}; + static int create_iec958_consumer(uint rate, uint sample_width, u8 *cs, size_t len) { @@ -21,6 +98,9 @@ static int create_iec958_consumer(uint rate, uint sample_width, return -EINVAL; switch (rate) { + case 0: + fs = IEC958_AES3_CON_FS_NOTID; + break; case 32000: fs = IEC958_AES3_CON_FS_32000; break; @@ -48,6 +128,9 @@ static int create_iec958_consumer(uint rate, uint sample_width, if (len > 4) { switch (sample_width) { + case 0: +
[PATCH 3/3] ASoC: dmaengine_pcm: document process callback
Add missing description of process callback. Fixes: 78648092ef46 ("ASoC: dmaengine_pcm: add processing support") Signed-off-by: Olivier Moysan --- include/sound/dmaengine_pcm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 47ef486852ed..e3481eebdd98 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -118,6 +118,8 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * PCM substream. Will be called from the PCM drivers hwparams callback. * @compat_request_channel: Callback to request a DMA channel for platforms * which do not use devicetree. + * @process: Callback used to apply processing on samples transferred from/to + * user space. * @compat_filter_fn: Will be used as the filter function when requesting a * channel for platforms which do not use devicetree. The filter parameter * will be the DAI's DMA data. -- 1.9.1