[Patch v5 00/12] Add audio support for LPC32XX CPUs
This pach set is to bring back audio to machines with a LPC32XX CPU. The legacy LPC32XX SoC used to have audio spport in linux 2.6.27. The support was dropped due to lack of interest from mainaeners.
Piotr Wojtaszczyk (12): dt-bindings: dma: pl08x: Add dma-cells description dt-bindings: dma: Add lpc32xx DMA mux binding ASoC: dt-bindings: lpc32xx: Add lpc32xx i2s DT binding ARM: dts: lpc32xx: Use simple-mfd for clock control block ARM: dts: lpc32xx: Add missing dma properties ARM: dts: lpc32xx: Add missing i2s properties clk: lpc32xx: initialize regmap using parent syscon dmaengine: Add dma router for pl08x in LPC32XX SoC ARM: lpc32xx: Remove pl08x platform data in favor for device tree mtd: rawnand: lpx32xx: Request DMA channels using DT entries ASoC: fsl: Add i2s and pcm drivers for LPC32xx CPUs i2x: pnx: Fix potential deadlock warning from del_timer_sync() call in isr
.../devicetree/bindings/dma/arm-pl08x.yaml | 7 + .../bindings/dma/nxp,lpc3220-dmamux.yaml | 49 +++ .../bindings/sound/nxp,lpc3220-i2s.yaml | 73 ++++ MAINTAINERS | 20 + arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 53 ++- arch/arm/mach-lpc32xx/phy3250.c | 54 --- drivers/clk/Kconfig | 1 + drivers/clk/nxp/clk-lpc32xx.c | 26 +- drivers/dma/Kconfig | 9 + drivers/dma/Makefile | 1 + drivers/dma/lpc32xx-dmamux.c | 195 +++++++++ drivers/i2c/busses/i2c-pnx.c | 48 +-- drivers/mtd/nand/raw/lpc32xx_mlc.c | 26 +- drivers/mtd/nand/raw/lpc32xx_slc.c | 26 +- sound/soc/fsl/Kconfig | 7 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/lpc3xxx-i2s.c | 375 ++++++++++++++++++ sound/soc/fsl/lpc3xxx-i2s.h | 79 ++++ sound/soc/fsl/lpc3xxx-pcm.c | 72 ++++ 19 files changed, 993 insertions(+), 130 deletions(-) create mode 100644 Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml create mode 100644 Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml create mode 100644 drivers/dma/lpc32xx-dmamux.c create mode 100644 sound/soc/fsl/lpc3xxx-i2s.c create mode 100644 sound/soc/fsl/lpc3xxx-i2s.h create mode 100644 sound/soc/fsl/lpc3xxx-pcm.c
Recover dma-cells description from the legacy DT binding.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com Fixes: 6f64aa5746d2 ("dt-bindings: dma: convert arm-pl08x to yaml") Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org --- Changes for v4: - This patch is new in v4
Documentation/devicetree/bindings/dma/arm-pl08x.yaml | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/Documentation/devicetree/bindings/dma/arm-pl08x.yaml b/Documentation/devicetree/bindings/dma/arm-pl08x.yaml index ab25ae63d2c3..191215d36c85 100644 --- a/Documentation/devicetree/bindings/dma/arm-pl08x.yaml +++ b/Documentation/devicetree/bindings/dma/arm-pl08x.yaml @@ -52,6 +52,13 @@ properties: clock-names: maxItems: 1
+ "#dma-cells": + const: 2 + description: | + First cell should contain the DMA request, + second cell should contain either 1 or 2 depending on + which AHB master that is used. + lli-bus-interface-ahb1: type: boolean description: if AHB master 1 is eligible for fetching LLIs
LPC32XX SoCs use pl080 dma controller which have few request signals multiplexed between peripherals. This binding describes how devices can use the multiplexed request signals.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - Corrected property order - Added maxItems to properties - Fixed example - Removed "N:: from the MAINTAINERS entry - Added Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com to LPC32XX maintainers
Changes for v4: - This patch is new in v4
.../bindings/dma/nxp,lpc3220-dmamux.yaml | 49 +++++++++++++++++++ MAINTAINERS | 9 ++++ 2 files changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml
diff --git a/Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml b/Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml new file mode 100644 index 000000000000..32f208744154 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/nxp,lpc3220-dmamux.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: DMA multiplexer for LPC32XX SoC (DMA request router) + +maintainers: + - J.M.B. Downing jonathan.downing@nautel.com + - Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com + +allOf: + - $ref: dma-router.yaml# + +properties: + compatible: + const: nxp,lpc3220-dmamux + + reg: + maxItems: 1 + + dma-masters: + description: phandle to a dma node compatible with arm,pl080 + maxItems: 1 + + "#dma-cells": + const: 3 + description: | + First two cells same as for device pointed in dma-masters. + Third cell represents mux value for the request. + +required: + - compatible + - reg + - dma-masters + +additionalProperties: false + +examples: + - | + dma-router@7c { + compatible = "nxp,lpc3220-dmamux"; + reg = <0x7c 0x8>; + dma-masters = <&dma>; + #dma-cells = <3>; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index aacccb376c28..79b44addc139 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2384,6 +2384,7 @@ N: lpc18xx
ARM/LPC32XX SOC SUPPORT M: Vladimir Zapolskiy vz@mleia.com +M: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://github.com/vzapolskiy/linux-lpc32xx.git @@ -2396,6 +2397,14 @@ F: drivers/usb/host/ohci-nxp.c F: drivers/watchdog/pnx4008_wdt.c N: lpc32xx
+LPC32XX DMAMUX SUPPORT +M: J.M.B. Downing jonathan.downing@nautel.com +M: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com +R: Vladimir Zapolskiy vz@mleia.com +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml + ARM/Marvell Dove/MV78xx0/Orion SOC support M: Andrew Lunn andrew@lunn.ch M: Sebastian Hesselbarth sebastian.hesselbarth@gmail.com
On 27/06/2024 17:00, Piotr Wojtaszczyk wrote:
LPC32XX SoCs use pl080 dma controller which have few request signals multiplexed between peripherals. This binding describes how devices can use the multiplexed request signals.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com
Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org
Best regards, Krzysztof
On Thu, 27 Jun 2024 17:00:20 +0200, Piotr Wojtaszczyk wrote:
LPC32XX SoCs use pl080 dma controller which have few request signals multiplexed between peripherals. This binding describes how devices can use the multiplexed request signals.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com
Changes for v5:
- Corrected property order
- Added maxItems to properties
- Fixed example
- Removed "N:: from the MAINTAINERS entry
- Added Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com to LPC32XX maintainers
Changes for v4:
- This patch is new in v4
.../bindings/dma/nxp,lpc3220-dmamux.yaml | 49 +++++++++++++++++++ MAINTAINERS | 9 ++++ 2 files changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml
Applied, thanks!
Add nxp,lpc3220-i2s DT binding documentation.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org --- Changes for v5: - Removed "N:" from the MAINTAINERS entry
Changes for v4: - Custom dma-vc-names property with standard dmas and dma-names - Added to MAINTAINERS
Changes for v3: - Added '$ref: dai-common.yaml#' and '#sound-dai-cells' - Dropped all clock-names, references - Dropped status property from the example - Added interrupts property - 'make dt_binding_check' pass
Changes for v2: - Added maintainers field - Dropped clock-names - Dropped unused unneded interrupts field
.../bindings/sound/nxp,lpc3220-i2s.yaml | 73 +++++++++++++++++++ MAINTAINERS | 9 +++ 2 files changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml
diff --git a/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml b/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml new file mode 100644 index 000000000000..40a0877a8aba --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nxp,lpc3220-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC32XX I2S Controller + +description: + The I2S controller in LPC32XX SoCs, ASoC DAI. + +maintainers: + - J.M.B. Downing jonathan.downing@nautel.com + - Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - nxp,lpc3220-i2s + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: input clock of the peripheral. + + dmas: + items: + - description: RX DMA Channel + - description: TX DMA Channel + + dma-names: + items: + - const: rx + - const: tx + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - interrupts + - clocks + - dmas + - dma-names + - '#sound-dai-cells' + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/lpc32xx-clock.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2s@20094000 { + compatible = "nxp,lpc3220-i2s"; + reg = <0x20094000 0x1000>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LPC32XX_CLK_I2S0>; + dmas = <&dma 0 1>, <&dma 13 1>; + dma-names = "rx", "tx"; + #sound-dai-cells = <0>; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 79b44addc139..ceec359c68fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8918,6 +8918,15 @@ S: Maintained F: sound/soc/fsl/fsl* F: sound/soc/fsl/imx*
+FREESCALE SOC LPC32XX SOUND DRIVERS +M: J.M.B. Downing jonathan.downing@nautel.com +M: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com +R: Vladimir Zapolskiy vz@mleia.com +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +L: linuxppc-dev@lists.ozlabs.org +S: Maintained +F: Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml + FREESCALE SOC SOUND QMC DRIVER M: Herve Codina herve.codina@bootlin.com L: alsa-devel@alsa-project.org (moderated for non-subscribers)
The clock control block shares registers with other Soc components
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - This patch is new in v5 - Split previous patch for lpc32xx.dtsi in to 3 patches
arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi index 974410918f35..8bf88d141e5b 100644 --- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi @@ -312,18 +312,17 @@ fab { compatible = "simple-bus"; ranges = <0x20000000 0x20000000 0x30000000>;
- /* System Control Block */ - scb { - compatible = "simple-bus"; - ranges = <0x0 0x40004000 0x00001000>; + syscon@40004000 { + compatible = "nxp,lpc3220-creg", "syscon", "simple-mfd"; + reg = <0x40004000 0x114>; #address-cells = <1>; #size-cells = <1>; + ranges = <0 0x40004000 0x114>;
clk: clock-controller@0 { compatible = "nxp,lpc3220-clk"; reg = <0x00 0x114>; #clock-cells = <1>; - clocks = <&xtal_32k>, <&xtal>; clock-names = "xtal_32k", "xtal"; };
Hi Piotr,
kernel test robot noticed the following build warnings:
[auto build test WARNING on vkoul-dmaengine/next] [also build test WARNING on robh/for-next linus/master v6.10-rc5 next-20240628] [cannot apply to broonie-sound/for-next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Piotr-Wojtaszczyk/dt-bindings... base: https://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git next patch link: https://lore.kernel.org/r/20240627150046.258795-5-piotr.wojtaszczyk%40timesy... patch subject: [Patch v5 04/12] ARM: dts: lpc32xx: Use simple-mfd for clock control block config: arm-randconfig-051-20240628 compiler: arm-linux-gnueabi-gcc (GCC) 13.2.0 dtschema version: 2024.6.dev3+g650bf2d reproduce (this is a W=1 build):
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Closes: https://lore.kernel.org/oe-kbuild-all/202406292138.A35Akeys-lkp@intel.com/
dtcheck warnings: (new ones prefixed by >>) arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: sd@20098000: Unevaluated properties are not allowed ('bus-width', 'cd-gpios', 'cd-inverted', 'wp-gpios' were unexpected) from schema $id: http://devicetree.org/schemas/mmc/arm,pl18x.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: i2c@400a0000: Unevaluated properties are not allowed ('clocks' was unexpected) from schema $id: http://devicetree.org/schemas/i2c/nxp,pnx-i2c.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/apb/i2c@400a0000/uda1380@18: failed to match any schema with compatible: ['nxp,uda1380'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: i2c@400a8000: Unevaluated properties are not allowed ('clocks' was unexpected) from schema $id: http://devicetree.org/schemas/i2c/nxp,pnx-i2c.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/apb/mpwm@400e8000: failed to match any schema with compatible: ['nxp,lpc3220-motor-pwm'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: fab: $nodename:0: 'fab' does not match '^([a-z][a-z0-9\-]+-bus|bus|localbus|soc|axi|ahb|apb)(@.+)?$' from schema $id: http://devicetree.org/schemas/simple-bus.yaml#
arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/syscon@40004000: failed to match any schema with compatible: ['nxp,lpc3220-creg', 'syscon', 'simple-mfd'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/syscon@40004000/clock-controller@0: failed to match any schema with compatible: ['nxp,lpc3220-clk']
arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/interrupt-controller@40008000: failed to match any schema with compatible: ['nxp,lpc3220-mic'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/interrupt-controller@4000c000: failed to match any schema with compatible: ['nxp,lpc3220-sic'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/interrupt-controller@40010000: failed to match any schema with compatible: ['nxp,lpc3220-sic'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/serial@40014000: failed to match any schema with compatible: ['nxp,lpc3220-hsuart'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/serial@40018000: failed to match any schema with compatible: ['nxp,lpc3220-hsuart'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/serial@4001c000: failed to match any schema with compatible: ['nxp,lpc3220-hsuart'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: rtc@40024000: 'clocks' does not match any of the regexes: 'pinctrl-[0-9]+' from schema $id: http://devicetree.org/schemas/rtc/trivial-rtc.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/gpio@40028000: failed to match any schema with compatible: ['nxp,lpc3220-gpio'] arch/arm/boot/dts/nxp/lpc/lpc3250-ea3250.dtb: /ahb/fab/timer@4002c000: failed to match any schema with compatible: ['nxp,lpc3220-timer'] -- arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: sd@20098000: Unevaluated properties are not allowed ('bus-width', 'cd-gpios', 'cd-inverted', 'vmmc-supply', 'wp-gpios' were unexpected) from schema $id: http://devicetree.org/schemas/mmc/arm,pl18x.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: i2c@400a0000: Unevaluated properties are not allowed ('clocks' was unexpected) from schema $id: http://devicetree.org/schemas/i2c/nxp,pnx-i2c.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/apb/i2c@400a0000/uda1380@18: failed to match any schema with compatible: ['nxp,uda1380'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: i2c@400a8000: Unevaluated properties are not allowed ('clocks' was unexpected) from schema $id: http://devicetree.org/schemas/i2c/nxp,pnx-i2c.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/apb/mpwm@400e8000: failed to match any schema with compatible: ['nxp,lpc3220-motor-pwm'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: fab: $nodename:0: 'fab' does not match '^([a-z][a-z0-9\-]+-bus|bus|localbus|soc|axi|ahb|apb)(@.+)?$' from schema $id: http://devicetree.org/schemas/simple-bus.yaml#
arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/syscon@40004000: failed to match any schema with compatible: ['nxp,lpc3220-creg', 'syscon', 'simple-mfd'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/syscon@40004000/clock-controller@0: failed to match any schema with compatible: ['nxp,lpc3220-clk']
arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/interrupt-controller@40008000: failed to match any schema with compatible: ['nxp,lpc3220-mic'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/interrupt-controller@4000c000: failed to match any schema with compatible: ['nxp,lpc3220-sic'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/interrupt-controller@40010000: failed to match any schema with compatible: ['nxp,lpc3220-sic'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/serial@40014000: failed to match any schema with compatible: ['nxp,lpc3220-hsuart'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/serial@40018000: failed to match any schema with compatible: ['nxp,lpc3220-hsuart'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/serial@4001c000: failed to match any schema with compatible: ['nxp,lpc3220-hsuart'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: rtc@40024000: 'clocks' does not match any of the regexes: 'pinctrl-[0-9]+' from schema $id: http://devicetree.org/schemas/rtc/trivial-rtc.yaml# arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/gpio@40028000: failed to match any schema with compatible: ['nxp,lpc3220-gpio'] arch/arm/boot/dts/nxp/lpc/lpc3250-phy3250.dtb: /ahb/fab/timer@4002c000: failed to match any schema with compatible: ['nxp,lpc3220-timer']
Adds properties declared in the new DT binding nxp,lpc3220-dmamux.yaml and corresponding phandles.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - This patch is new in v5 - Split previous patch for lpc32xx.dtsi in to 3 patches
arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi index 8bf88d141e5b..6135ce4dde61 100644 --- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi @@ -67,6 +67,8 @@ slc: flash@20020000 { reg = <0x20020000 0x1000>; clocks = <&clk LPC32XX_CLK_SLC>; status = "disabled"; + dmas = <&dma 1 1>; + dma-names = "rx-tx"; };
mlc: flash@200a8000 { @@ -75,6 +77,8 @@ mlc: flash@200a8000 { interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk LPC32XX_CLK_MLC>; status = "disabled"; + dmas = <&dma 12 1>; + dma-names = "rx-tx"; };
dma: dma@31000000 { @@ -83,6 +87,13 @@ dma: dma@31000000 { interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk LPC32XX_CLK_DMA>; clock-names = "apb_pclk"; + #dma-cells = <2>; + dma-channels = <8>; + dma-requests = <16>; + lli-bus-interface-ahb1; + mem-bus-interface-ahb1; + memcpy-burst-size = <256>; + memcpy-bus-width = <32>; };
usb { @@ -182,6 +193,8 @@ ssp0: spi@20084000 { clock-names = "apb_pclk"; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux 14 1 1>, <&dmamux 15 1 1>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -191,6 +204,8 @@ spi1: spi@20088000 { clocks = <&clk LPC32XX_CLK_SPI1>; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux 11 1 0>; + dma-names = "rx-tx"; status = "disabled"; };
@@ -206,6 +221,8 @@ ssp1: spi@2008c000 { clock-names = "apb_pclk"; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux 3 1 1>, <&dmamux 11 1 1>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -215,12 +232,16 @@ spi2: spi@20090000 { clocks = <&clk LPC32XX_CLK_SPI2>; #address-cells = <1>; #size-cells = <0>; + dmas = <&dmamux 3 1 0>; + dma-names = "rx-tx"; status = "disabled"; };
i2s0: i2s@20094000 { compatible = "nxp,lpc3220-i2s"; reg = <0x20094000 0x1000>; + dmas = <&dma 0 1>, <&dma 13 1>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -231,12 +252,16 @@ sd: sd@20098000 { <13 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk LPC32XX_CLK_SD>; clock-names = "apb_pclk"; + dmas = <&dma 4 1>; + dma-names = "rx"; status = "disabled"; };
i2s1: i2s@2009c000 { compatible = "nxp,lpc3220-i2s"; reg = <0x2009c000 0x1000>; + dmas = <&dma 2 1>, <&dmamux 10 1 1>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -326,6 +351,13 @@ clk: clock-controller@0 { clocks = <&xtal_32k>, <&xtal>; clock-names = "xtal_32k", "xtal"; }; + + dmamux: dma-router@7c { + compatible = "nxp,lpc3220-dmamux"; + reg = <0x7c 0x8>; + #dma-cells = <3>; + dma-masters = <&dma>; + }; };
mic: interrupt-controller@40008000 { @@ -361,6 +393,8 @@ uart1: serial@40014000 { compatible = "nxp,lpc3220-hsuart"; reg = <0x40014000 0x1000>; interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma 6 1>, <&dma 5 1>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -368,6 +402,8 @@ uart2: serial@40018000 { compatible = "nxp,lpc3220-hsuart"; reg = <0x40018000 0x1000>; interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma 8 1>, <&dma 7 1>; + dma-names = "rx", "tx"; status = "disabled"; };
@@ -375,6 +411,8 @@ uart7: serial@4001c000 { compatible = "nxp,lpc3220-hsuart"; reg = <0x4001c000 0x1000>; interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dmamux 10 1 0>, <&dma 9 1>; + dma-names = "rx", "tx"; status = "disabled"; };
Adds properties declared in the new DT binding nxp,lpc3220-i2s.yaml
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - This patch is new in v5 - Split previous patch for lpc32xx.dtsi in to 3 patches
arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi index 6135ce4dde61..c58dc127e59f 100644 --- a/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi +++ b/arch/arm/boot/dts/nxp/lpc/lpc32xx.dtsi @@ -240,8 +240,11 @@ spi2: spi@20090000 { i2s0: i2s@20094000 { compatible = "nxp,lpc3220-i2s"; reg = <0x20094000 0x1000>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LPC32XX_CLK_I2S0>; dmas = <&dma 0 1>, <&dma 13 1>; dma-names = "rx", "tx"; + #sound-dai-cells = <0>; status = "disabled"; };
@@ -260,8 +263,11 @@ sd: sd@20098000 { i2s1: i2s@2009c000 { compatible = "nxp,lpc3220-i2s"; reg = <0x2009c000 0x1000>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LPC32XX_CLK_I2S1>; dmas = <&dma 2 1>, <&dmamux 10 1 1>; dma-names = "rx", "tx"; + #sound-dai-cells = <0>; status = "disabled"; };
This allows to share the regmap with other simple-mfd devices like nxp,lpc32xx-dmamux
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - Add fallback regmap for previous simple-bus DT entry
Changes for v4: - This patch is new in v4
drivers/clk/Kconfig | 1 + drivers/clk/nxp/clk-lpc32xx.c | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3e9099504fad..85ef57d5cccf 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -346,6 +346,7 @@ config COMMON_CLK_LOONGSON2 config COMMON_CLK_NXP def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX) select REGMAP_MMIO if ARCH_LPC32XX + select MFD_SYSCON if ARCH_LPC32XX select MFD_SYSCON if ARCH_LPC18XX help Support for clock providers on NXP platforms. diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index d0f870eff0d6..b8de7f66d1b5 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -7,6 +7,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/of_address.h> +#include <linux/mfd/syscon.h> #include <linux/regmap.h>
#include <dt-bindings/clock/lpc32xx-clock.h> @@ -1511,18 +1512,21 @@ static void __init lpc32xx_clk_init(struct device_node *np) return; }
- base = of_iomap(np, 0); - if (!base) { - pr_err("failed to map system control block registers\n"); - return; - } - - clk_regmap = regmap_init_mmio(NULL, base, &lpc32xx_scb_regmap_config); + clk_regmap = syscon_node_to_regmap(np->parent); if (IS_ERR(clk_regmap)) { - pr_err("failed to regmap system control block: %ld\n", - PTR_ERR(clk_regmap)); - iounmap(base); - return; + /* fallback to mmio if syscon fails */ + base = of_iomap(np, 0); + if (!base) { + pr_err("failed to map system control block registers\n"); + return; + } + clk_regmap = regmap_init_mmio(NULL, base, &lpc32xx_scb_regmap_config); + if (IS_ERR(clk_regmap)) { + pr_err("failed to regmap system control block: %ld\n", + PTR_ERR(clk_regmap)); + iounmap(base); + return; + } }
/*
LPC32XX connects few of its peripherals to pl08x DMA thru a multiplexer, this driver allows to route a signal request line thru the multiplexer for given peripheral.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - Fix struct declaration order - Removed unused variables - Break search loop if expected lpc32xx_muxes[i].signal is found
Changes for v4: - This patch is new in v4
MAINTAINERS | 1 + drivers/dma/Kconfig | 9 ++ drivers/dma/Makefile | 1 + drivers/dma/lpc32xx-dmamux.c | 195 +++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+) create mode 100644 drivers/dma/lpc32xx-dmamux.c
diff --git a/MAINTAINERS b/MAINTAINERS index ceec359c68fc..118d48747641 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2404,6 +2404,7 @@ R: Vladimir Zapolskiy vz@mleia.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml +F: drivers/dma/lpc32xx-dmamux.c
ARM/Marvell Dove/MV78xx0/Orion SOC support M: Andrew Lunn andrew@lunn.ch diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 002a5ec80620..aeace3d7e066 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -378,6 +378,15 @@ config LPC18XX_DMAMUX Enable support for DMA on NXP LPC18xx/43xx platforms with PL080 and multiplexed DMA request lines.
+config LPC32XX_DMAMUX + bool "NXP LPC32xx DMA MUX for PL080" + depends on ARCH_LPC32XX || COMPILE_TEST + depends on OF && AMBA_PL08X + select MFD_SYSCON + help + Support for PL080 multiplexed DMA request lines on + LPC32XX platrofm. + config LS2X_APB_DMA tristate "Loongson LS2X APB DMA support" depends on LOONGARCH || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 802ca916f05f..6f1350b62e7f 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-y += idxd/ obj-$(CONFIG_K3_DMA) += k3dma.o obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o +obj-$(CONFIG_LPC32XX_DMAMUX) += lpc32xx-dmamux.o obj-$(CONFIG_LS2X_APB_DMA) += ls2x-apb-dma.o obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o obj-$(CONFIG_MILBEAUT_XDMAC) += milbeaut-xdmac.o diff --git a/drivers/dma/lpc32xx-dmamux.c b/drivers/dma/lpc32xx-dmamux.c new file mode 100644 index 000000000000..351d7e23e615 --- /dev/null +++ b/drivers/dma/lpc32xx-dmamux.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright 2024 Timesys Corporation piotr.wojtaszczyk@timesys.com +// +// Based on TI DMA Crossbar driver by: +// Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com +// Author: Peter Ujfalusi peter.ujfalusi@ti.com + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_dma.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/spinlock.h> + +#define LPC32XX_SSP_CLK_CTRL 0x78 +#define LPC32XX_I2S_CLK_CTRL 0x7c + +struct lpc32xx_dmamux { + int signal; + char *name_sel0; + char *name_sel1; + int muxval; + int muxreg; + int bit; + bool busy; +}; + +struct lpc32xx_dmamux_data { + struct dma_router dmarouter; + struct regmap *reg; + spinlock_t lock; /* protects busy status flag */ +}; + +/* From LPC32x0 User manual "3.2.1 DMA request signals" */ +static struct lpc32xx_dmamux lpc32xx_muxes[] = { + { + .signal = 3, + .name_sel0 = "spi2-rx-tx", + .name_sel1 = "ssp1-rx", + .muxreg = LPC32XX_SSP_CLK_CTRL, + .bit = 5, + }, + { + .signal = 10, + .name_sel0 = "uart7-rx", + .name_sel1 = "i2s1-dma1", + .muxreg = LPC32XX_I2S_CLK_CTRL, + .bit = 4, + }, + { + .signal = 11, + .name_sel0 = "spi1-rx-tx", + .name_sel1 = "ssp1-tx", + .muxreg = LPC32XX_SSP_CLK_CTRL, + .bit = 4, + }, + { + .signal = 14, + .name_sel0 = "none", + .name_sel1 = "ssp0-rx", + .muxreg = LPC32XX_SSP_CLK_CTRL, + .bit = 3, + }, + { + .signal = 15, + .name_sel0 = "none", + .name_sel1 = "ssp0-tx", + .muxreg = LPC32XX_SSP_CLK_CTRL, + .bit = 2, + }, +}; + +static void lpc32xx_dmamux_release(struct device *dev, void *route_data) +{ + struct lpc32xx_dmamux_data *dmamux = dev_get_drvdata(dev); + struct lpc32xx_dmamux *mux = route_data; + + dev_dbg(dev, "releasing dma request signal %d routed to %s\n", + mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1); + + guard(spinlock)(&dmamux->lock); + + mux->busy = false; +} + +static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct platform_device *pdev = of_find_device_by_node(ofdma->of_node); + struct device *dev = &pdev->dev; + struct lpc32xx_dmamux_data *dmamux = platform_get_drvdata(pdev); + unsigned long flags; + struct lpc32xx_dmamux *mux = NULL; + int i; + + if (dma_spec->args_count != 3) { + dev_err(&pdev->dev, "invalid number of dma mux args\n"); + return ERR_PTR(-EINVAL); + } + + for (i = 0; i < ARRAY_SIZE(lpc32xx_muxes); i++) { + if (lpc32xx_muxes[i].signal == dma_spec->args[0]) { + mux = &lpc32xx_muxes[i]; + break; + } + } + if (!mux) { + dev_err(&pdev->dev, "invalid mux request number: %d\n", + dma_spec->args[0]); + return ERR_PTR(-EINVAL); + } + + if (dma_spec->args[2] > 1) { + dev_err(&pdev->dev, "invalid dma mux value: %d\n", + dma_spec->args[1]); + return ERR_PTR(-EINVAL); + } + + /* The of_node_put() will be done in the core for the node */ + dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); + if (!dma_spec->np) { + dev_err(&pdev->dev, "can't get dma master\n"); + return ERR_PTR(-EINVAL); + } + + spin_lock_irqsave(&dmamux->lock, flags); + if (mux->busy) { + spin_unlock_irqrestore(&dmamux->lock, flags); + dev_err(dev, "dma request signal %d busy, routed to %s\n", + mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1); + of_node_put(dma_spec->np); + return ERR_PTR(-EBUSY); + } + + mux->busy = true; + mux->muxval = dma_spec->args[2] ? BIT(mux->bit) : 0; + + regmap_update_bits(dmamux->reg, mux->muxreg, BIT(mux->bit), mux->muxval); + spin_unlock_irqrestore(&dmamux->lock, flags); + + dma_spec->args[2] = 0; + dma_spec->args_count = 2; + + dev_dbg(dev, "dma request signal %d routed to %s\n", + mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1); + + return mux; +} + +static int lpc32xx_dmamux_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct lpc32xx_dmamux_data *dmamux; + + dmamux = devm_kzalloc(&pdev->dev, sizeof(*dmamux), GFP_KERNEL); + if (!dmamux) + return -ENOMEM; + + dmamux->reg = syscon_node_to_regmap(np->parent); + if (IS_ERR(dmamux->reg)) { + dev_err(&pdev->dev, "syscon lookup failed\n"); + return PTR_ERR(dmamux->reg); + } + + spin_lock_init(&dmamux->lock); + platform_set_drvdata(pdev, dmamux); + dmamux->dmarouter.dev = &pdev->dev; + dmamux->dmarouter.route_free = lpc32xx_dmamux_release; + + return of_dma_router_register(np, lpc32xx_dmamux_reserve, + &dmamux->dmarouter); +} + +static const struct of_device_id lpc32xx_dmamux_match[] = { + { .compatible = "nxp,lpc3220-dmamux" }, + {}, +}; + +static struct platform_driver lpc32xx_dmamux_driver = { + .probe = lpc32xx_dmamux_probe, + .driver = { + .name = "lpc32xx-dmamux", + .of_match_table = lpc32xx_dmamux_match, + }, +}; + +static int __init lpc32xx_dmamux_init(void) +{ + return platform_driver_register(&lpc32xx_dmamux_driver); +} +arch_initcall(lpc32xx_dmamux_init);
On Thu, Jun 27, 2024 at 05:00:26PM +0200, Piotr Wojtaszczyk wrote:
LPC32XX connects few of its peripherals to pl08x DMA thru a multiplexer,
^^^ through? I google 'thru', most said it is informal spell of 'through'.
this driver allows to route a signal request line thru the multiplexer for given peripheral.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com
Changes for v5:
- Fix struct declaration order
- Removed unused variables
- Break search loop if expected lpc32xx_muxes[i].signal is found
Changes for v4:
- This patch is new in v4
MAINTAINERS | 1 + drivers/dma/Kconfig | 9 ++ drivers/dma/Makefile | 1 + drivers/dma/lpc32xx-dmamux.c | 195 +++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+) create mode 100644 drivers/dma/lpc32xx-dmamux.c
diff --git a/MAINTAINERS b/MAINTAINERS index ceec359c68fc..118d48747641 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2404,6 +2404,7 @@ R: Vladimir Zapolskiy vz@mleia.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/dma/nxp,lpc3220-dmamux.yaml +F: drivers/dma/lpc32xx-dmamux.c
ARM/Marvell Dove/MV78xx0/Orion SOC support M: Andrew Lunn andrew@lunn.ch diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 002a5ec80620..aeace3d7e066 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -378,6 +378,15 @@ config LPC18XX_DMAMUX Enable support for DMA on NXP LPC18xx/43xx platforms with PL080 and multiplexed DMA request lines.
+config LPC32XX_DMAMUX
- bool "NXP LPC32xx DMA MUX for PL080"
- depends on ARCH_LPC32XX || COMPILE_TEST
- depends on OF && AMBA_PL08X
- select MFD_SYSCON
- help
Support for PL080 multiplexed DMA request lines on
LPC32XX platrofm.
config LS2X_APB_DMA tristate "Loongson LS2X APB DMA support" depends on LOONGARCH || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 802ca916f05f..6f1350b62e7f 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-y += idxd/ obj-$(CONFIG_K3_DMA) += k3dma.o obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o +obj-$(CONFIG_LPC32XX_DMAMUX) += lpc32xx-dmamux.o obj-$(CONFIG_LS2X_APB_DMA) += ls2x-apb-dma.o obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o obj-$(CONFIG_MILBEAUT_XDMAC) += milbeaut-xdmac.o diff --git a/drivers/dma/lpc32xx-dmamux.c b/drivers/dma/lpc32xx-dmamux.c new file mode 100644 index 000000000000..351d7e23e615 --- /dev/null +++ b/drivers/dma/lpc32xx-dmamux.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright 2024 Timesys Corporation piotr.wojtaszczyk@timesys.com +// +// Based on TI DMA Crossbar driver by: +// Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com +// Author: Peter Ujfalusi peter.ujfalusi@ti.com
+#include <linux/err.h> +#include <linux/init.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_dma.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/spinlock.h>
+#define LPC32XX_SSP_CLK_CTRL 0x78 +#define LPC32XX_I2S_CLK_CTRL 0x7c
+struct lpc32xx_dmamux {
- int signal;
- char *name_sel0;
- char *name_sel1;
- int muxval;
- int muxreg;
- int bit;
- bool busy;
+};
+struct lpc32xx_dmamux_data {
- struct dma_router dmarouter;
- struct regmap *reg;
- spinlock_t lock; /* protects busy status flag */
+};
+/* From LPC32x0 User manual "3.2.1 DMA request signals" */ +static struct lpc32xx_dmamux lpc32xx_muxes[] = {
- {
.signal = 3,
.name_sel0 = "spi2-rx-tx",
.name_sel1 = "ssp1-rx",
.muxreg = LPC32XX_SSP_CLK_CTRL,
.bit = 5,
- },
- {
.signal = 10,
.name_sel0 = "uart7-rx",
.name_sel1 = "i2s1-dma1",
.muxreg = LPC32XX_I2S_CLK_CTRL,
.bit = 4,
- },
- {
.signal = 11,
.name_sel0 = "spi1-rx-tx",
.name_sel1 = "ssp1-tx",
.muxreg = LPC32XX_SSP_CLK_CTRL,
.bit = 4,
- },
- {
.signal = 14,
.name_sel0 = "none",
.name_sel1 = "ssp0-rx",
.muxreg = LPC32XX_SSP_CLK_CTRL,
.bit = 3,
- },
- {
.signal = 15,
.name_sel0 = "none",
.name_sel1 = "ssp0-tx",
.muxreg = LPC32XX_SSP_CLK_CTRL,
.bit = 2,
- },
+};
+static void lpc32xx_dmamux_release(struct device *dev, void *route_data) +{
- struct lpc32xx_dmamux_data *dmamux = dev_get_drvdata(dev);
- struct lpc32xx_dmamux *mux = route_data;
- dev_dbg(dev, "releasing dma request signal %d routed to %s\n",
mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1);
- guard(spinlock)(&dmamux->lock);
- mux->busy = false;
+}
+static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
+{
- struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
- struct device *dev = &pdev->dev;
- struct lpc32xx_dmamux_data *dmamux = platform_get_drvdata(pdev);
- unsigned long flags;
- struct lpc32xx_dmamux *mux = NULL;
- int i;
It'd better keep reverse christmas tree order.
- if (dma_spec->args_count != 3) {
dev_err(&pdev->dev, "invalid number of dma mux args\n");
return ERR_PTR(-EINVAL);
- }
- for (i = 0; i < ARRAY_SIZE(lpc32xx_muxes); i++) {
if (lpc32xx_muxes[i].signal == dma_spec->args[0]) {
mux = &lpc32xx_muxes[i];
break;
}
- }
Add empty line here.
- if (!mux) {
dev_err(&pdev->dev, "invalid mux request number: %d\n",
dma_spec->args[0]);
return ERR_PTR(-EINVAL);
- }
- if (dma_spec->args[2] > 1) {
dev_err(&pdev->dev, "invalid dma mux value: %d\n",
dma_spec->args[1]);
return ERR_PTR(-EINVAL);
- }
- /* The of_node_put() will be done in the core for the node */
- dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
- if (!dma_spec->np) {
dev_err(&pdev->dev, "can't get dma master\n");
return ERR_PTR(-EINVAL);
- }
- spin_lock_irqsave(&dmamux->lock, flags);
you already use guard in lpc32xx_dmamux_release(). here is better place to use guard also.
because it spin lock, better use scoped_guard() {}.
- if (mux->busy) {
spin_unlock_irqrestore(&dmamux->lock, flags);
dev_err(dev, "dma request signal %d busy, routed to %s\n",
mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1);
of_node_put(dma_spec->np);
return ERR_PTR(-EBUSY);
- }
- mux->busy = true;
- mux->muxval = dma_spec->args[2] ? BIT(mux->bit) : 0;
- regmap_update_bits(dmamux->reg, mux->muxreg, BIT(mux->bit), mux->muxval);
- spin_unlock_irqrestore(&dmamux->lock, flags);
- dma_spec->args[2] = 0;
- dma_spec->args_count = 2;
Why need update dma_spec here? Suppose it just pass down dt information.
- dev_dbg(dev, "dma request signal %d routed to %s\n",
mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1);
- return mux;
+}
+static int lpc32xx_dmamux_probe(struct platform_device *pdev) +{
- struct device_node *np = pdev->dev.of_node;
- struct lpc32xx_dmamux_data *dmamux;
- dmamux = devm_kzalloc(&pdev->dev, sizeof(*dmamux), GFP_KERNEL);
- if (!dmamux)
return -ENOMEM;
- dmamux->reg = syscon_node_to_regmap(np->parent);
- if (IS_ERR(dmamux->reg)) {
dev_err(&pdev->dev, "syscon lookup failed\n");
return PTR_ERR(dmamux->reg);
- }
- spin_lock_init(&dmamux->lock);
- platform_set_drvdata(pdev, dmamux);
- dmamux->dmarouter.dev = &pdev->dev;
- dmamux->dmarouter.route_free = lpc32xx_dmamux_release;
- return of_dma_router_register(np, lpc32xx_dmamux_reserve,
&dmamux->dmarouter);
+}
+static const struct of_device_id lpc32xx_dmamux_match[] = {
- { .compatible = "nxp,lpc3220-dmamux" },
- {},
+};
+static struct platform_driver lpc32xx_dmamux_driver = {
- .probe = lpc32xx_dmamux_probe,
- .driver = {
.name = "lpc32xx-dmamux",
.of_match_table = lpc32xx_dmamux_match,
- },
+};
+static int __init lpc32xx_dmamux_init(void) +{
- return platform_driver_register(&lpc32xx_dmamux_driver);
+}
+arch_initcall(lpc32xx_dmamux_init);
2.25.1
With the driver for nxp,lpc3220-dmamux we can remove the pl08x platform data and let pl08x driver to create peripheral channels from the DT properties.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v4: - This patch is new in v4
arch/arm/mach-lpc32xx/phy3250.c | 54 --------------------------------- 1 file changed, 54 deletions(-)
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c index 66701bf43248..0c7797a0e44e 100644 --- a/arch/arm/mach-lpc32xx/phy3250.c +++ b/arch/arm/mach-lpc32xx/phy3250.c @@ -16,64 +16,10 @@ #include <asm/mach/arch.h> #include "common.h"
-static struct pl08x_channel_data pl08x_slave_channels[] = { - { - .bus_id = "nand-slc", - .min_signal = 1, /* SLC NAND Flash */ - .max_signal = 1, - .periph_buses = PL08X_AHB1, - }, - { - .bus_id = "nand-mlc", - .min_signal = 12, /* MLC NAND Flash */ - .max_signal = 12, - .periph_buses = PL08X_AHB1, - }, -}; - -static int pl08x_get_signal(const struct pl08x_channel_data *cd) -{ - return cd->min_signal; -} - -static void pl08x_put_signal(const struct pl08x_channel_data *cd, int ch) -{ -} - -static struct pl08x_platform_data pl08x_pd = { - /* Some reasonable memcpy defaults */ - .memcpy_burst_size = PL08X_BURST_SZ_256, - .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS, - .slave_channels = &pl08x_slave_channels[0], - .num_slave_channels = ARRAY_SIZE(pl08x_slave_channels), - .get_xfer_signal = pl08x_get_signal, - .put_xfer_signal = pl08x_put_signal, - .lli_buses = PL08X_AHB1, - .mem_buses = PL08X_AHB1, -}; - -static struct lpc32xx_slc_platform_data lpc32xx_slc_data = { - .dma_filter = pl08x_filter_id, -}; - -static struct lpc32xx_mlc_platform_data lpc32xx_mlc_data = { - .dma_filter = pl08x_filter_id, -}; - -static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = { - OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd), - OF_DEV_AUXDATA("nxp,lpc3220-slc", 0x20020000, "20020000.flash", - &lpc32xx_slc_data), - OF_DEV_AUXDATA("nxp,lpc3220-mlc", 0x200a8000, "200a8000.flash", - &lpc32xx_mlc_data), - { } -}; - static void __init lpc3250_machine_init(void) { lpc32xx_serial_init();
- of_platform_default_populate(NULL, lpc32xx_auxdata_lookup, NULL); }
static const char *const lpc32xx_dt_compat[] __initconst = {
Move away from pl08x platform data towards device tree.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - Added fallback dma channel request for backward compatibility with DMA with platform data instead DT
Changes for v4: - This patch is new in v4
drivers/mtd/nand/raw/lpc32xx_mlc.c | 26 +++++++++++++++----------- drivers/mtd/nand/raw/lpc32xx_slc.c | 26 +++++++++++++++----------- 2 files changed, 30 insertions(+), 22 deletions(-)
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index 677fcb03f9be..92cebe871bb4 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -574,18 +574,22 @@ static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host) struct mtd_info *mtd = nand_to_mtd(&host->nand_chip); dma_cap_mask_t mask;
- if (!host->pdata || !host->pdata->dma_filter) { - dev_err(mtd->dev.parent, "no DMA platform data\n"); - return -ENOENT; - } - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, - "nand-mlc"); + host->dma_chan = dma_request_chan(mtd->dev.parent, "rx-tx"); if (!host->dma_chan) { - dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); - return -EBUSY; + /* fallback to request using platform data */ + if (!host->pdata || !host->pdata->dma_filter) { + dev_err(mtd->dev.parent, "no DMA platform data\n"); + return -ENOENT; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, "nand-mlc"); + + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } }
/* diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 1c5fa855b9f2..3b7e3d259785 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -721,18 +721,22 @@ static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host) struct mtd_info *mtd = nand_to_mtd(&host->nand_chip); dma_cap_mask_t mask;
- if (!host->pdata || !host->pdata->dma_filter) { - dev_err(mtd->dev.parent, "no DMA platform data\n"); - return -ENOENT; - } - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, - "nand-slc"); + host->dma_chan = dma_request_chan(mtd->dev.parent, "rx-tx"); if (!host->dma_chan) { - dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); - return -EBUSY; + /* fallback to request using platform data */ + if (!host->pdata || !host->pdata->dma_filter) { + dev_err(mtd->dev.parent, "no DMA platform data\n"); + return -ENOENT; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, host->pdata->dma_filter, "nand-slc"); + + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } }
return 0;
On Thu, 2024-06-27 at 15:00:28 UTC, Piotr Wojtaszczyk wrote:
Move away from pl08x platform data towards device tree.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com
Applied to https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next, thanks.
Miquel
This driver was ported from an old version in linux 2.6.27 and adjusted for the new ASoC framework and DMA API.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - Removed "N:" from the MAINTAINERS entry - Removed unused filter_data and flags variables
Changes for v4: - Add to MAINTAINERS - Use guard(mutex)(&i2s_info_p->lock) when possible - Request dma chennels using DT entries in devm_snd_dmaengine_pcm_register
Changes for v3: - Split previous commit for separate subsystems - Add support and jonathan.downing@nautel.com as a maintainer for the driver - Replaced `SND_SOC` config dependency with COMPILE_TEST - Moved `snd-soc-fsl-lpc3xxx-y` in Makefile up in the list to maintain alfabedical order - Changed comment to c++ format - replaced custom absd32() with standard abs() function - Added clock provider check in lpc3xxx_i2s_set_dai_fmt() - Removed empty lpc32xx_i2s_remove() function - Reworked i2s regs definitions to include LPC3XXX prefix - Replaced custom _BIT, _SBD with standard BIT and FIELD_PREP macros
Changes for v2: - Coding Style cleanup - Use dev_err_probe() for error handling in probe function - Removed unneded err_clk_disable label - Removed empty function - Droped of_match_ptr in lpc32xx_i2s_match DT match table - ASoC struct adjustmes for the latest 6.10-rc3 kernel
MAINTAINERS | 1 + sound/soc/fsl/Kconfig | 7 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/lpc3xxx-i2s.c | 375 ++++++++++++++++++++++++++++++++++++ sound/soc/fsl/lpc3xxx-i2s.h | 79 ++++++++ sound/soc/fsl/lpc3xxx-pcm.c | 72 +++++++ 6 files changed, 536 insertions(+) create mode 100644 sound/soc/fsl/lpc3xxx-i2s.c create mode 100644 sound/soc/fsl/lpc3xxx-i2s.h create mode 100644 sound/soc/fsl/lpc3xxx-pcm.c
diff --git a/MAINTAINERS b/MAINTAINERS index 118d48747641..adfe07a99c1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8927,6 +8927,7 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: linuxppc-dev@lists.ozlabs.org S: Maintained F: Documentation/devicetree/bindings/sound/nxp,lpc3220-i2s.yaml +F: sound/soc/fsl/lpc3xxx-*
FREESCALE SOC SOUND QMC DRIVER M: Herve Codina herve.codina@bootlin.com diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 270726c134b3..72f2d4d15696 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -130,6 +130,13 @@ config SND_SOC_FSL_RPMSG This option is only useful for out-of-tree drivers since in-tree drivers select it automatically.
+config SND_SOC_FSL_LPC3XXX + tristate "SoC Audio for NXP LPC32XX CPUs" + depends on ARCH_LPC32XX || COMPILE_TEST + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for the LPC3XXX I2S interface. + config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 2fe78eed3a48..2a61e2f96438 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o snd-soc-fsl-audmix-y := fsl_audmix.o snd-soc-fsl-asoc-card-y := fsl-asoc-card.o snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o +snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o snd-soc-fsl-sai-y := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o @@ -29,6 +30,7 @@ snd-soc-fsl-qmc-audio-y := fsl_qmc_audio.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o +obj-$(CONFIG_SND_SOC_FSL_LPC3XXX) += snd-soc-fsl-lpc3xxx.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o diff --git a/sound/soc/fsl/lpc3xxx-i2s.c b/sound/soc/fsl/lpc3xxx-i2s.c new file mode 100644 index 000000000000..0e5b4d5202ff --- /dev/null +++ b/sound/soc/fsl/lpc3xxx-i2s.c @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Author: Kevin Wells kevin.wells@nxp.com +// +// Copyright (C) 2008 NXP Semiconductors +// Copyright 2023 Timesys Corporation piotr.wojtaszczyk@timesys.com + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/dmaengine_pcm.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include "lpc3xxx-i2s.h" + +#define I2S_PLAYBACK_FLAG 0x1 +#define I2S_CAPTURE_FLAG 0x2 + +#define LPC3XXX_I2S_RATES ( \ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) + +#define LPC3XXX_I2S_FORMATS ( \ + SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static void __lpc3xxx_find_clkdiv(u32 *clkx, u32 *clky, int freq, int xbytes, u32 clkrate) +{ + u32 i2srate; + u32 idxx, idyy; + u32 savedbitclkrate, diff, trate, baseclk; + + /* Adjust rate for sample size (bits) and 2 channels and offset for + * divider in clock output + */ + i2srate = (freq / 100) * 2 * (8 * xbytes); + i2srate = i2srate << 1; + clkrate = clkrate / 100; + baseclk = clkrate; + *clkx = 1; + *clky = 1; + + /* Find the best divider */ + *clkx = *clky = 0; + savedbitclkrate = 0; + diff = ~0; + for (idxx = 1; idxx < 0xFF; idxx++) { + for (idyy = 1; idyy < 0xFF; idyy++) { + trate = (baseclk * idxx) / idyy; + if (abs(trate - i2srate) < diff) { + diff = abs(trate - i2srate); + savedbitclkrate = trate; + *clkx = idxx; + *clky = idyy; + } + } + } +} + +static int lpc3xxx_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct device *dev = i2s_info_p->dev; + u32 flag; + int ret = 0; + + guard(mutex)(&i2s_info_p->lock); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + flag = I2S_PLAYBACK_FLAG; + else + flag = I2S_CAPTURE_FLAG; + + if (flag & i2s_info_p->streams_in_use) { + dev_warn(dev, "I2S channel is busy\n"); + ret = -EBUSY; + return ret; + } + + if (i2s_info_p->streams_in_use == 0) { + ret = clk_prepare_enable(i2s_info_p->clk); + if (ret) { + dev_err(dev, "Can't enable clock, err=%d\n", ret); + return ret; + } + } + + i2s_info_p->streams_in_use |= flag; + return 0; +} + +static void lpc3xxx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regs = i2s_info_p->regs; + const u32 stop_bits = (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP); + u32 flag; + + guard(mutex)(&i2s_info_p->lock); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + flag = I2S_PLAYBACK_FLAG; + regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, 0); + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, stop_bits, stop_bits); + } else { + flag = I2S_CAPTURE_FLAG; + regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, 0); + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, stop_bits, stop_bits); + } + i2s_info_p->streams_in_use &= ~flag; + + if (i2s_info_p->streams_in_use == 0) + clk_disable_unprepare(i2s_info_p->clk); +} + +static int lpc3xxx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + + /* Will use in HW params later */ + i2s_info_p->freq = freq; + + return 0; +} + +static int lpc3xxx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct device *dev = i2s_info_p->dev; + + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) { + dev_warn(dev, "unsupported bus format %d\n", fmt); + return -EINVAL; + } + + if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) { + dev_warn(dev, "unsupported clock provider %d\n", fmt); + return -EINVAL; + } + + return 0; +} + +static int lpc3xxx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct device *dev = i2s_info_p->dev; + struct regmap *regs = i2s_info_p->regs; + int xfersize; + u32 tmp, clkx, clky; + + tmp = LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + tmp |= LPC3XXX_I2S_WW8 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW8_HP); + xfersize = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + tmp |= LPC3XXX_I2S_WW16 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW16_HP); + xfersize = 2; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + tmp |= LPC3XXX_I2S_WW32 | LPC3XXX_I2S_WS_HP(LPC3XXX_I2S_WW32_HP); + xfersize = 4; + break; + + default: + dev_warn(dev, "Unsupported audio data format %d\n", params_format(params)); + return -EINVAL; + } + + if (params_channels(params) == 1) + tmp |= LPC3XXX_I2S_MONO; + + __lpc3xxx_find_clkdiv(&clkx, &clky, i2s_info_p->freq, xfersize, i2s_info_p->clkrate); + + dev_dbg(dev, "Stream : %s\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + dev_dbg(dev, "Desired clock rate : %d\n", i2s_info_p->freq); + dev_dbg(dev, "Base clock rate : %d\n", i2s_info_p->clkrate); + dev_dbg(dev, "Transfer size (bytes) : %d\n", xfersize); + dev_dbg(dev, "Clock divider (x) : %d\n", clkx); + dev_dbg(dev, "Clock divider (y) : %d\n", clky); + dev_dbg(dev, "Channels : %d\n", params_channels(params)); + dev_dbg(dev, "Data format : %s\n", "I2S"); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_write(regs, LPC3XXX_REG_I2S_DMA1, + LPC3XXX_I2S_DMA1_TX_EN | LPC3XXX_I2S_DMA0_TX_DEPTH(4)); + regmap_write(regs, LPC3XXX_REG_I2S_TX_RATE, (clkx << 8) | clky); + regmap_write(regs, LPC3XXX_REG_I2S_DAO, tmp); + } else { + regmap_write(regs, LPC3XXX_REG_I2S_DMA0, + LPC3XXX_I2S_DMA0_RX_EN | LPC3XXX_I2S_DMA1_RX_DEPTH(4)); + regmap_write(regs, LPC3XXX_REG_I2S_RX_RATE, (clkx << 8) | clky); + regmap_write(regs, LPC3XXX_REG_I2S_DAI, tmp); + } + + return 0; +} + +static int lpc3xxx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(cpu_dai); + struct regmap *regs = i2s_info_p->regs; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, + LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP); + else + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, + LPC3XXX_I2S_STOP, LPC3XXX_I2S_STOP); + break; + + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAO, + (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0); + else + regmap_update_bits(regs, LPC3XXX_REG_I2S_DAI, + (LPC3XXX_I2S_RESET | LPC3XXX_I2S_STOP), 0); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int lpc3xxx_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct lpc3xxx_i2s_info *i2s_info_p = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &i2s_info_p->playback_dma_config, + &i2s_info_p->capture_dma_config); + return 0; +} + +const struct snd_soc_dai_ops lpc3xxx_i2s_dai_ops = { + .probe = lpc3xxx_i2s_dai_probe, + .startup = lpc3xxx_i2s_startup, + .shutdown = lpc3xxx_i2s_shutdown, + .trigger = lpc3xxx_i2s_trigger, + .hw_params = lpc3xxx_i2s_hw_params, + .set_sysclk = lpc3xxx_i2s_set_dai_sysclk, + .set_fmt = lpc3xxx_i2s_set_dai_fmt, +}; + +struct snd_soc_dai_driver lpc3xxx_i2s_dai_driver = { + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = LPC3XXX_I2S_RATES, + .formats = LPC3XXX_I2S_FORMATS, + }, + .ops = &lpc3xxx_i2s_dai_ops, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, +}; + +static const struct snd_soc_component_driver lpc32xx_i2s_component = { + .name = "lpc32xx-i2s", + .legacy_dai_naming = 1, +}; + +static const struct regmap_config lpc32xx_i2s_regconfig = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = LPC3XXX_REG_I2S_RX_RATE, +}; + +static int lpc32xx_i2s_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lpc3xxx_i2s_info *i2s_info_p; + struct resource *res; + void __iomem *iomem; + int ret; + + i2s_info_p = devm_kzalloc(dev, sizeof(*i2s_info_p), GFP_KERNEL); + if (!i2s_info_p) + return -ENOMEM; + + platform_set_drvdata(pdev, i2s_info_p); + i2s_info_p->dev = dev; + + iomem = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(iomem)) + return dev_err_probe(dev, PTR_ERR(iomem), "Can't map registers\n"); + + i2s_info_p->regs = devm_regmap_init_mmio(dev, iomem, &lpc32xx_i2s_regconfig); + if (IS_ERR(i2s_info_p->regs)) + return dev_err_probe(dev, PTR_ERR(i2s_info_p->regs), + "failed to init register map: %d\n", ret); + + i2s_info_p->clk = devm_clk_get(dev, NULL); + if (IS_ERR(i2s_info_p->clk)) + return dev_err_probe(dev, PTR_ERR(i2s_info_p->clk), "Can't get clock\n"); + + i2s_info_p->clkrate = clk_get_rate(i2s_info_p->clk); + if (i2s_info_p->clkrate == 0) + return dev_err_probe(dev, -EINVAL, "Invalid returned clock rate\n"); + + mutex_init(&i2s_info_p->lock); + + ret = devm_snd_soc_register_component(dev, &lpc32xx_i2s_component, + &lpc3xxx_i2s_dai_driver, 1); + if (ret) + return dev_err_probe(dev, ret, "Can't register cpu_dai component\n"); + + i2s_info_p->playback_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_TX_FIFO); + i2s_info_p->playback_dma_config.maxburst = 4; + + i2s_info_p->capture_dma_config.addr = (dma_addr_t)(res->start + LPC3XXX_REG_I2S_RX_FIFO); + i2s_info_p->capture_dma_config.maxburst = 4; + + ret = lpc3xxx_pcm_register(pdev); + if (ret) + return dev_err_probe(dev, ret, "Can't register pcm component\n"); + + return 0; +} + +static const struct of_device_id lpc32xx_i2s_match[] = { + { .compatible = "nxp,lpc3220-i2s" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_i2s_match); + +static struct platform_driver lpc32xx_i2s_driver = { + .probe = lpc32xx_i2s_probe, + .driver = { + .name = "lpc3xxx-i2s", + .of_match_table = lpc32xx_i2s_match, + }, +}; + +module_platform_driver(lpc32xx_i2s_driver); + +MODULE_AUTHOR("Kevin Wells kevin.wells@nxp.com"); +MODULE_AUTHOR("Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com"); +MODULE_DESCRIPTION("ASoC LPC3XXX I2S interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/lpc3xxx-i2s.h b/sound/soc/fsl/lpc3xxx-i2s.h new file mode 100644 index 000000000000..eec755448478 --- /dev/null +++ b/sound/soc/fsl/lpc3xxx-i2s.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Author: Kevin Wells kevin.wells@nxp.com + * + * Copyright (C) 2008 NXP Semiconductors + * Copyright 2023 Timesys Corporation piotr.wojtaszczyk@timesys.com + */ + +#ifndef __SOUND_SOC_LPC3XXX_I2S_H +#define __SOUND_SOC_LPC3XXX_I2S_H + +#include <linux/types.h> +#include <linux/regmap.h> + +struct lpc3xxx_i2s_info { + struct device *dev; + struct clk *clk; + struct mutex lock; /* To serialize user-space access */ + struct regmap *regs; + u32 streams_in_use; + u32 clkrate; + int freq; + struct snd_dmaengine_dai_dma_data playback_dma_config; + struct snd_dmaengine_dai_dma_data capture_dma_config; +}; + +int lpc3xxx_pcm_register(struct platform_device *pdev); + +/* I2S controller register offsets */ +#define LPC3XXX_REG_I2S_DAO 0x00 +#define LPC3XXX_REG_I2S_DAI 0x04 +#define LPC3XXX_REG_I2S_TX_FIFO 0x08 +#define LPC3XXX_REG_I2S_RX_FIFO 0x0C +#define LPC3XXX_REG_I2S_STAT 0x10 +#define LPC3XXX_REG_I2S_DMA0 0x14 +#define LPC3XXX_REG_I2S_DMA1 0x18 +#define LPC3XXX_REG_I2S_IRQ 0x1C +#define LPC3XXX_REG_I2S_TX_RATE 0x20 +#define LPC3XXX_REG_I2S_RX_RATE 0x24 + +/* i2s_daO i2s_dai register definitions */ +#define LPC3XXX_I2S_WW8 FIELD_PREP(0x3, 0) /* Word width is 8bit */ +#define LPC3XXX_I2S_WW16 FIELD_PREP(0x3, 1) /* Word width is 16bit */ +#define LPC3XXX_I2S_WW32 FIELD_PREP(0x3, 3) /* Word width is 32bit */ +#define LPC3XXX_I2S_MONO BIT(2) /* Mono */ +#define LPC3XXX_I2S_STOP BIT(3) /* Stop, diables the access to FIFO, mutes the channel */ +#define LPC3XXX_I2S_RESET BIT(4) /* Reset the channel */ +#define LPC3XXX_I2S_WS_SEL BIT(5) /* Channel Master(0) or slave(1) mode select */ +#define LPC3XXX_I2S_WS_HP(s) FIELD_PREP(0x7FC0, s) /* Word select half period - 1 */ +#define LPC3XXX_I2S_MUTE BIT(15) /* Mute the channel, Transmit channel only */ + +#define LPC3XXX_I2S_WW32_HP 0x1f /* Word select half period for 32bit word width */ +#define LPC3XXX_I2S_WW16_HP 0x0f /* Word select half period for 16bit word width */ +#define LPC3XXX_I2S_WW8_HP 0x7 /* Word select half period for 8bit word width */ + +/* i2s_stat register definitions */ +#define LPC3XXX_I2S_IRQ_STAT BIT(0) +#define LPC3XXX_I2S_DMA0_REQ BIT(1) +#define LPC3XXX_I2S_DMA1_REQ BIT(2) + +/* i2s_dma0 Configuration register definitions */ +#define LPC3XXX_I2S_DMA0_RX_EN BIT(0) /* Enable RX DMA1 */ +#define LPC3XXX_I2S_DMA0_TX_EN BIT(1) /* Enable TX DMA1 */ +#define LPC3XXX_I2S_DMA0_RX_DEPTH(s) FIELD_PREP(0xF00, s) /* Set the DMA1 RX Request level */ +#define LPC3XXX_I2S_DMA0_TX_DEPTH(s) FIELD_PREP(0xF0000, s) /* Set the DMA1 TX Request level */ + +/* i2s_dma1 Configuration register definitions */ +#define LPC3XXX_I2S_DMA1_RX_EN BIT(0) /* Enable RX DMA1 */ +#define LPC3XXX_I2S_DMA1_TX_EN BIT(1) /* Enable TX DMA1 */ +#define LPC3XXX_I2S_DMA1_RX_DEPTH(s) FIELD_PREP(0x700, s) /* Set the DMA1 RX Request level */ +#define LPC3XXX_I2S_DMA1_TX_DEPTH(s) FIELD_PREP(0x70000, s) /* Set the DMA1 TX Request level */ + +/* i2s_irq register definitions */ +#define LPC3XXX_I2S_RX_IRQ_EN BIT(0) /* Enable RX IRQ */ +#define LPC3XXX_I2S_TX_IRQ_EN BIT(1) /* Enable TX IRQ */ +#define LPC3XXX_I2S_IRQ_RX_DEPTH(s) FIELD_PREP(0xFF00, s) /* valid values ar 0 to 7 */ +#define LPC3XXX_I2S_IRQ_TX_DEPTH(s) FIELD_PREP(0xFF0000, s) /* valid values ar 0 to 7 */ + +#endif diff --git a/sound/soc/fsl/lpc3xxx-pcm.c b/sound/soc/fsl/lpc3xxx-pcm.c new file mode 100644 index 000000000000..c0d499b9b8ba --- /dev/null +++ b/sound/soc/fsl/lpc3xxx-pcm.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Author: Kevin Wells kevin.wells@nxp.com +// +// Copyright (C) 2008 NXP Semiconductors +// Copyright 2023 Timesys Corporation piotr.wojtaszczyk@timesys.com + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/amba/pl08x.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/dmaengine_pcm.h> +#include <sound/soc.h> + +#include "lpc3xxx-i2s.h" + +#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_U32_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) + +static const struct snd_pcm_hardware lpc3xxx_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME), + .formats = STUB_FORMATS, + .period_bytes_min = 128, + .period_bytes_max = 2048, + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 128 * 1024 +}; + +static const struct snd_dmaengine_pcm_config lpc3xxx_dmaengine_pcm_config = { + .pcm_hardware = &lpc3xxx_pcm_hardware, + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .compat_filter_fn = pl08x_filter_id, + .prealloc_buffer_size = 128 * 1024, +}; + +const struct snd_soc_component_driver lpc3xxx_soc_platform_driver = { + .name = "lpc32xx-pcm", +}; + +int lpc3xxx_pcm_register(struct platform_device *pdev) +{ + int ret; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &lpc3xxx_dmaengine_pcm_config, 0); + if (ret) { + dev_err(&pdev->dev, "failed to register dmaengine: %d\n", ret); + return ret; + } + + return devm_snd_soc_register_component(&pdev->dev, &lpc3xxx_soc_platform_driver, + NULL, 0); +} +EXPORT_SYMBOL(lpc3xxx_pcm_register);
When del_timer_sync() is called in an interrupt context it throws a warning because of potential deadlock. The timer is used only to exit from wait_for_completion() after a timeout so replacing the call with wait_for_completion_timeout() allows to remove the problematic timer and its related functions altogether.
Signed-off-by: Piotr Wojtaszczyk piotr.wojtaszczyk@timesys.com --- Changes for v5: - Replaced wait_for_completion() with wait_for_completion_timeout(). - Removed unneded "alg_data->mif.timer" and its functions - Request irq with devm_request_irq() as before the patch - Renamed the patch and reword description for the new way to fix the warning
Changes for v4: - Request irq with devm_request_threaded_irq() to prevent the warning
drivers/i2c/busses/i2c-pnx.c | 48 ++++++++---------------------------- 1 file changed, 10 insertions(+), 38 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a12525b3186b..f448505d5468 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -15,7 +15,6 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/i2c.h> -#include <linux/timer.h> #include <linux/completion.h> #include <linux/platform_device.h> #include <linux/io.h> @@ -32,7 +31,6 @@ struct i2c_pnx_mif { int ret; /* Return value */ int mode; /* Interface mode */ struct completion complete; /* I/O completion */ - struct timer_list timer; /* Timeout */ u8 * buf; /* Data buffer */ int len; /* Length of data buffer */ int order; /* RX Bytes to order via TX */ @@ -117,24 +115,6 @@ static inline int wait_reset(struct i2c_pnx_algo_data *data) return (timeout <= 0); }
-static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) -{ - struct timer_list *timer = &alg_data->mif.timer; - unsigned long expires = msecs_to_jiffies(alg_data->timeout); - - if (expires <= 1) - expires = 2; - - del_timer_sync(timer); - - dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n", - jiffies, expires); - - timer->expires = jiffies + expires; - - add_timer(timer); -} - /** * i2c_pnx_start - start a device * @slave_addr: slave address @@ -259,8 +239,6 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), I2C_REG_CTL(alg_data));
- del_timer_sync(&alg_data->mif.timer); - dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine.\n", __func__); @@ -276,8 +254,6 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), I2C_REG_CTL(alg_data));
- /* Stop timer. */ - del_timer_sync(&alg_data->mif.timer); dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine after zero-xfer.\n", __func__); @@ -364,8 +340,6 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) mcntrl_drmie | mcntrl_daie); iowrite32(ctl, I2C_REG_CTL(alg_data));
- /* Kill timer. */ - del_timer_sync(&alg_data->mif.timer); complete(&alg_data->mif.complete); } } @@ -400,8 +374,6 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) mcntrl_drmie); iowrite32(ctl, I2C_REG_CTL(alg_data));
- /* Stop timer, to prevent timeout. */ - del_timer_sync(&alg_data->mif.timer); complete(&alg_data->mif.complete); } else if (stat & mstatus_nai) { /* Slave did not acknowledge, generate a STOP */ @@ -419,8 +391,6 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) /* Our return value. */ alg_data->mif.ret = -EIO;
- /* Stop timer, to prevent timeout. */ - del_timer_sync(&alg_data->mif.timer); complete(&alg_data->mif.complete); } else { /* @@ -453,9 +423,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; }
-static void i2c_pnx_timeout(struct timer_list *t) +static void i2c_pnx_timeout(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer); u32 ctl;
dev_err(&alg_data->adapter.dev, @@ -472,7 +441,6 @@ static void i2c_pnx_timeout(struct timer_list *t) iowrite32(ctl, I2C_REG_CTL(alg_data)); wait_reset(alg_data); alg_data->mif.ret = -EIO; - complete(&alg_data->mif.complete); }
static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) @@ -514,6 +482,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_msg *pmsg; int rc = 0, completed = 0, i; struct i2c_pnx_algo_data *alg_data = adap->algo_data; + unsigned long time_left; u32 stat;
dev_dbg(&alg_data->adapter.dev, @@ -548,7 +517,6 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", __func__, alg_data->mif.mode, alg_data->mif.len);
- i2c_pnx_arm_timer(alg_data);
/* initialize the completion var */ init_completion(&alg_data->mif.complete); @@ -564,7 +532,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) break;
/* Wait for completion */ - wait_for_completion(&alg_data->mif.complete); + time_left = wait_for_completion_timeout(&alg_data->mif.complete, + alg_data->timeout); + if (time_left == 0) + i2c_pnx_timeout(alg_data);
if (!(rc = alg_data->mif.ret)) completed++; @@ -653,7 +624,10 @@ static int i2c_pnx_probe(struct platform_device *pdev) alg_data->adapter.algo_data = alg_data; alg_data->adapter.nr = pdev->id;
- alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT; + alg_data->timeout = msecs_to_jiffies(I2C_PNX_TIMEOUT_DEFAULT); + if (alg_data->timeout <= 1) + alg_data->timeout = 2; + #ifdef CONFIG_OF alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node); if (pdev->dev.of_node) { @@ -673,8 +647,6 @@ static int i2c_pnx_probe(struct platform_device *pdev) if (IS_ERR(alg_data->clk)) return PTR_ERR(alg_data->clk);
- timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0); - snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), "%s", pdev->name);
On 27/06/2024 17:00, Piotr Wojtaszczyk wrote:
When del_timer_sync() is called in an interrupt context it throws a warning because of potential deadlock. The timer is used only to exit from wait_for_completion() after a timeout so replacing the call with wait_for_completion_timeout() allows to remove the problematic timer and its related functions altogether.
Subject typo: i2c
Best regards, Krzysztof
On Thu, 27 Jun 2024 17:00:18 +0200, Piotr Wojtaszczyk wrote:
This pach set is to bring back audio to machines with a LPC32XX CPU. The legacy LPC32XX SoC used to have audio spport in linux 2.6.27. The support was dropped due to lack of interest from mainaeners.
Piotr Wojtaszczyk (12): dt-bindings: dma: pl08x: Add dma-cells description dt-bindings: dma: Add lpc32xx DMA mux binding ASoC: dt-bindings: lpc32xx: Add lpc32xx i2s DT binding ARM: dts: lpc32xx: Use simple-mfd for clock control block ARM: dts: lpc32xx: Add missing dma properties ARM: dts: lpc32xx: Add missing i2s properties clk: lpc32xx: initialize regmap using parent syscon dmaengine: Add dma router for pl08x in LPC32XX SoC ARM: lpc32xx: Remove pl08x platform data in favor for device tree mtd: rawnand: lpx32xx: Request DMA channels using DT entries ASoC: fsl: Add i2s and pcm drivers for LPC32xx CPUs i2x: pnx: Fix potential deadlock warning from del_timer_sync() call in isr
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[03/12] ASoC: dt-bindings: lpc32xx: Add lpc32xx i2s DT binding commit: 752fea92d9b3e4255a2f75e7efa6fe148562ccbf [11/12] ASoC: fsl: Add i2s and pcm drivers for LPC32xx CPUs commit: 0959de657a10cc40b2cc41cff9169ab0e0fd4456
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (7)
-
Frank Li
-
kernel test robot
-
Krzysztof Kozlowski
-
Mark Brown
-
Miquel Raynal
-
Piotr Wojtaszczyk
-
Rob Herring (Arm)