i2s: stm32h7: add i2s support for stm32h7 mcu family

This commit modifies the I2S driver to work for STM32H7
family of MCU's. Currently only TX is working.

Tested on nucleo_stm32h743zi. Requires dma1 & dmamux1 to be enabled.

Signed-off-by: Emil Lindqvist <emil@lindq.gr>
This commit is contained in:
Emil Lindqvist 2023-11-01 11:54:23 +01:00 committed by Alberto Escolar
commit ed6da68f5b
7 changed files with 153 additions and 32 deletions

View file

@ -10,7 +10,7 @@ menuconfig I2S_STM32
select DMA
help
Enable I2S support on the STM32 family of processors.
(Tested on the STM32F4 series)
(Tested on the STM32F4 & STM32H7 series)
if I2S_STM32

View file

@ -22,11 +22,7 @@
#include <zephyr/irq.h>
LOG_MODULE_REGISTER(i2s_ll_stm32);
/* FIXME change to
* #if __DCACHE_PRESENT == 1
* when cache support is added
*/
#if 0
#if __DCACHE_PRESENT == 1
#define DCACHE_INVALIDATE(addr, size) \
SCB_InvalidateDCache_by_Addr((uint32_t *)addr, size)
#define DCACHE_CLEAN(addr, size) \
@ -187,6 +183,9 @@ static int i2s_stm32_configure(const struct device *dev, enum i2s_dir dir,
int ret;
if (dir == I2S_DIR_RX) {
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
return -ENOSYS;
#endif
stream = &dev_data->rx;
} else if (dir == I2S_DIR_TX) {
stream = &dev_data->tx;
@ -549,7 +548,11 @@ static void dma_rx_callback(const struct device *dma_dev, void *arg,
ret = reload_dma(stream->dev_dma, stream->dma_channel,
&stream->dma_cfg,
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
(void *)LL_SPI_DMA_GetRxRegAddr(cfg->i2s),
#else
(void *)LL_SPI_DMA_GetRegAddr(cfg->i2s),
#endif
stream->mem_block,
stream->cfg.block_size);
if (ret < 0) {
@ -634,7 +637,11 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg,
ret = reload_dma(stream->dev_dma, stream->dma_channel,
&stream->dma_cfg,
stream->mem_block,
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
(void *)LL_SPI_DMA_GetTxRegAddr(cfg->i2s),
#else
(void *)LL_SPI_DMA_GetRegAddr(cfg->i2s),
#endif
stream->cfg.block_size);
if (ret < 0) {
LOG_DBG("Failed to start TX DMA transfer: %d", ret);
@ -649,6 +656,7 @@ tx_disable:
static uint32_t i2s_stm32_irq_count;
static uint32_t i2s_stm32_irq_ovr_count;
static uint32_t i2s_stm32_irq_udr_count;
static void i2s_stm32_isr(const struct device *dev)
{
@ -665,6 +673,12 @@ static void i2s_stm32_isr(const struct device *dev)
LL_I2S_ClearFlag_OVR(cfg->i2s);
}
/* NOTE: UDR error must be explicitly cleared on STM32H7 */
if (LL_I2S_IsActiveFlag_UDR(cfg->i2s)) {
i2s_stm32_irq_udr_count++;
LL_I2S_ClearFlag_UDR(cfg->i2s);
}
i2s_stm32_irq_count++;
}
@ -736,7 +750,11 @@ static int rx_stream_start(struct stream *stream, const struct device *dev)
ret = start_dma(stream->dev_dma, stream->dma_channel,
&stream->dma_cfg,
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
(void *)LL_SPI_DMA_GetRxRegAddr(cfg->i2s),
#else
(void *)LL_SPI_DMA_GetRegAddr(cfg->i2s),
#endif
stream->src_addr_increment, stream->mem_block,
stream->dst_addr_increment, stream->fifo_threshold,
stream->cfg.block_size);
@ -747,8 +765,17 @@ static int rx_stream_start(struct stream *stream, const struct device *dev)
LL_I2S_EnableDMAReq_RX(cfg->i2s);
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
LL_I2S_EnableIT_OVR(cfg->i2s);
LL_I2S_EnableIT_UDR(cfg->i2s);
LL_I2S_EnableIT_FRE(cfg->i2s);
LL_I2S_Enable(cfg->i2s);
LL_SPI_StartMasterTransfer(cfg->i2s);
#else
LL_I2S_EnableIT_ERR(cfg->i2s);
LL_I2S_Enable(cfg->i2s);
#endif
return 0;
}
@ -781,7 +808,11 @@ static int tx_stream_start(struct stream *stream, const struct device *dev)
ret = start_dma(stream->dev_dma, stream->dma_channel,
&stream->dma_cfg,
stream->mem_block, stream->src_addr_increment,
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
(void *)LL_SPI_DMA_GetTxRegAddr(cfg->i2s),
#else
(void *)LL_SPI_DMA_GetRegAddr(cfg->i2s),
#endif
stream->dst_addr_increment, stream->fifo_threshold,
stream->cfg.block_size);
if (ret < 0) {
@ -791,8 +822,17 @@ static int tx_stream_start(struct stream *stream, const struct device *dev)
LL_I2S_EnableDMAReq_TX(cfg->i2s);
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
LL_I2S_EnableIT_OVR(cfg->i2s);
LL_I2S_EnableIT_UDR(cfg->i2s);
LL_I2S_EnableIT_FRE(cfg->i2s);
LL_I2S_Enable(cfg->i2s);
LL_SPI_StartMasterTransfer(cfg->i2s);
#else
LL_I2S_EnableIT_ERR(cfg->i2s);
LL_I2S_Enable(cfg->i2s);
#endif
return 0;
}
@ -802,7 +842,13 @@ static void rx_stream_disable(struct stream *stream, const struct device *dev)
const struct i2s_stm32_cfg *cfg = dev->config;
LL_I2S_DisableDMAReq_RX(cfg->i2s);
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
LL_I2S_DisableIT_OVR(cfg->i2s);
LL_I2S_DisableIT_UDR(cfg->i2s);
LL_I2S_DisableIT_FRE(cfg->i2s);
#else
LL_I2S_DisableIT_ERR(cfg->i2s);
#endif
dma_stop(stream->dev_dma, stream->dma_channel);
if (stream->mem_block != NULL) {
@ -820,7 +866,13 @@ static void tx_stream_disable(struct stream *stream, const struct device *dev)
const struct i2s_stm32_cfg *cfg = dev->config;
LL_I2S_DisableDMAReq_TX(cfg->i2s);
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s)
LL_I2S_DisableIT_OVR(cfg->i2s);
LL_I2S_DisableIT_UDR(cfg->i2s);
LL_I2S_DisableIT_FRE(cfg->i2s);
#else
LL_I2S_DisableIT_ERR(cfg->i2s);
#endif
dma_stop(stream->dev_dma, stream->dma_channel);
if (stream->mem_block != NULL) {

View file

@ -466,6 +466,48 @@
status = "disabled";
};
i2s1: i2s@40013000 {
compatible = "st,stm32h7-i2s", "st,stm32-i2s";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40013000 0x400>;
clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>,
<&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>;
dmas = <&dmamux1 0 38 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH)
&dmamux1 1 37 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>;
dma-names = "tx", "rx";
interrupts = <35 3>;
status = "disabled";
};
i2s2: i2s@40003800 {
compatible = "st,stm32h7-i2s", "st,stm32-i2s";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40003800 0x400>;
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00004000>,
<&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>;
dmas = <&dmamux1 0 40 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH)
&dmamux1 1 39 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>;
dma-names = "tx", "rx";
interrupts = <36 0>;
status = "disabled";
};
i2s3: i2s@40003c00 {
compatible = "st,stm32h7-i2s", "st,stm32-i2s";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40003c00 0x400>;
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00008000>,
<&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>;
dmas = <&dmamux1 0 62 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH)
&dmamux1 1 61 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>;
dma-names = "tx", "rx";
interrupts = <51 0>;
status = "disabled";
};
fdcan1: can@4000a000 {
compatible = "st,stm32h7-fdcan";
reg = <0x4000a000 0x400>, <0x4000ac00 0x350>;

View file

@ -79,6 +79,19 @@
status = "disabled";
};
i2s6: i2s@58001400 {
compatible = "st,stm32h7-i2s", "st,stm32-i2s";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x58001400 0x400>;
clocks = <&rcc STM32_CLOCK_BUS_APB4 0x00000020>,
<&rcc STM32_SRC_PLL1_Q SPI6_SEL(0)>;
dmas = <&dmamux2 0 12 0x20440 &dmamux2 1 11 0x20480>;
dma-names = "tx", "rx";
interrupts = <86 0>;
status = "disabled";
};
rng: rng@48021800 {
nist-config = <0xf00d00>;
health-test-magic = <0x17590abc>;

View file

@ -0,0 +1,31 @@
# Copyright (c) 2018, STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
# Common fields for STM32 I2S peripherals.
include: [i2s-controller.yaml, pinctrl-device.yaml]
properties:
reg:
required: true
interrupts:
required: true
dmas:
required: true
dma-names:
required: true
pinctrl-0:
required: true
pinctrl-names:
required: true
mck-enabled:
type: boolean
description: |
Master Clock Output function.
An mck pin must be listed within pinctrl-0 when enabling this property.

View file

@ -5,29 +5,4 @@ description: STM32 I2S controller
compatible: "st,stm32-i2s"
include: [i2s-controller.yaml, pinctrl-device.yaml]
properties:
reg:
required: true
interrupts:
required: true
dmas:
required: true
dma-names:
required: true
pinctrl-0:
required: true
pinctrl-names:
required: true
mck-enabled:
type: boolean
description: |
Master Clock Output function.
An mck pin must be listed within pinctrl-0 when enabling this property.
include: st,stm32-i2s-common.yaml

View file

@ -0,0 +1,8 @@
# Copyright (c) 2018, STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
description: STM32H7 I2S controller
compatible: "st,stm32h7-i2s"
include: st,stm32-i2s-common.yaml