diff --git a/drivers/i2s/i2s_stm32_sai.c b/drivers/i2s/i2s_stm32_sai.c index dc41dd35fc1c7..e80fdd41dc425 100644 --- a/drivers/i2s/i2s_stm32_sai.c +++ b/drivers/i2s/i2s_stm32_sai.c @@ -287,7 +287,7 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) hdma->Init.Mode = DMA_NORMAL; #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32L4X) || \ - defined(CONFIG_SOC_SERIES_STM32G4X) + defined(CONFIG_SOC_SERIES_STM32G4X) || defined(CONFIG_SOC_SERIES_STM32L5X) hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma->Init.Priority = DMA_PRIORITY_HIGH; @@ -312,7 +312,7 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) hdma->Init.Direction = DMA_MEMORY_TO_PERIPH; #if !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32L4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) + !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) hdma->Init.SrcInc = DMA_SINC_INCREMENTED; hdma->Init.DestInc = DMA_DINC_FIXED; #endif @@ -322,7 +322,7 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) hdma->Init.Direction = DMA_PERIPH_TO_MEMORY; #if !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32L4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) + !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) hdma->Init.SrcInc = DMA_SINC_FIXED; hdma->Init.DestInc = DMA_DINC_INCREMENTED; #endif @@ -342,7 +342,7 @@ static int i2s_stm32_sai_dma_init(const struct device *dev) return -EIO; } #elif !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32L4X) && \ - !defined(CONFIG_SOC_SERIES_STM32G4X) + !defined(CONFIG_SOC_SERIES_STM32G4X) && !defined(CONFIG_SOC_SERIES_STM32L5X) if (HAL_DMA_ConfigChannelAttributes(&dev_data->hdma, DMA_CHANNEL_NPRIV) != HAL_OK) { LOG_ERR("HAL_DMA_ConfigChannelAttributes: "); return -EIO; diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index 4102b9b5088fe..96d0691c0fb8e 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -2,12 +2,13 @@ * Copyright (c) 2021 The Chromium OS Authors * Copyright (c) 2020 Linaro Limited * Copyright (c) 2024 STMicroelectronics + * Copyright (c) 2025 Mario Paja * * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include #include #include #include @@ -120,6 +121,12 @@ compatible = "st,stm32l4-pll-clock"; status = "disabled"; }; + + pllsai1: pllsai1 { + #clock-cells = <0>; + compatible = "st,stm32l4-pllsai-clock"; + status = "disabled"; + }; }; soc { @@ -737,6 +744,30 @@ clocks = <&rcc STM32_CLOCK(AHB3, 0)>; status = "disabled"; }; + + sai1_a: sai1@40015404 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015404 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 21)>, + <&rcc STM32_SRC_PLLSAI1_P SAI1_SEL(0)>; + dmas = <&dma1 1 37 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS)>; + status = "disabled"; + }; + + sai1_b: sai1@40015424 { + compatible = "st,stm32-sai"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40015424 0x20>; + clocks = <&rcc STM32_CLOCK(APB2, 21)>, + <&rcc STM32_SRC_PLLSAI1_P SAI1_SEL(0)>; + dmas = <&dma1 2 38 (STM32_DMA_MODE_NORMAL | STM32_DMA_PRIORITY_HIGH | + STM32_DMA_16BITS)>; + status = "disabled"; + }; }; die_temp: dietemp { diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index 9b80fe60e24b1..ccce256482bfd 100644 --- a/include/zephyr/drivers/clock_control/stm32_clock_control.h +++ b/include/zephyr/drivers/clock_control/stm32_clock_control.h @@ -41,9 +41,10 @@ #include #elif defined(CONFIG_SOC_SERIES_STM32L1X) #include -#elif defined(CONFIG_SOC_SERIES_STM32L4X) || \ - defined(CONFIG_SOC_SERIES_STM32L5X) +#elif defined(CONFIG_SOC_SERIES_STM32L4X) #include +#elif defined(CONFIG_SOC_SERIES_STM32L5X) +#include #elif defined(CONFIG_SOC_SERIES_STM32MP2X) #include #elif defined(CONFIG_SOC_SERIES_STM32WBX) diff --git a/include/zephyr/dt-bindings/clock/stm32l4_clock.h b/include/zephyr/dt-bindings/clock/stm32l4_clock.h index 7fe6e514bce4c..cdef7de2b6426 100644 --- a/include/zephyr/dt-bindings/clock/stm32l4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l4_clock.h @@ -20,7 +20,7 @@ #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB2 /** Domain clocks */ -/* RM0351/RM0432/RM0438, § Clock configuration register (RCC_CCIPRx) */ +/* RM0351/RM0432, § Clock configuration register (RCC_CCIPRx) */ /** System clock */ /* defined in stm32_common_clocks.h */ diff --git a/include/zephyr/dt-bindings/clock/stm32l5_clock.h b/include/zephyr/dt-bindings/clock/stm32l5_clock.h new file mode 100644 index 0000000000000..451f004b04085 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/stm32l5_clock.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 Mario Paja + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L5_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L5_CLOCK_H_ + +#include "stm32_common_clocks.h" + +/** Bus clocks */ +#define STM32_CLOCK_BUS_AHB1 0x048 +#define STM32_CLOCK_BUS_AHB2 0x04c +#define STM32_CLOCK_BUS_AHB3 0x050 +#define STM32_CLOCK_BUS_APB1 0x058 +#define STM32_CLOCK_BUS_APB1_2 0x05c +#define STM32_CLOCK_BUS_APB2 0x060 + +#define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 +#define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB2 + +/** Domain clocks */ +/* RM0438, § Clock configuration register (RCC_CCIPRx) */ + +/** System clock */ +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI48 + 1) +/** Bus clock */ +#define STM32_SRC_PCLK (STM32_SRC_MSI + 1) +#define STM32_SRC_TIMPCLK1 (STM32_SRC_PCLK + 1) +#define STM32_SRC_TIMPCLK2 (STM32_SRC_TIMPCLK1 + 1) +/** PLL clock outputs */ +#define STM32_SRC_PLL_P (STM32_SRC_TIMPCLK2 + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) +/* PLLSAI1 clocks */ +#define STM32_SRC_PLLSAI1_P (STM32_SRC_PLL_R + 1) +#define STM32_SRC_PLLSAI1_Q (STM32_SRC_PLLSAI1_P + 1) +#define STM32_SRC_PLLSAI1_R (STM32_SRC_PLLSAI1_Q + 1) +/* PLLSAI2 clocks */ +#define STM32_SRC_PLLSAI2_P (STM32_SRC_PLLSAI1_R + 1) +#define STM32_SRC_PLLSAI2_Q (STM32_SRC_PLLSAI2_P + 1) +#define STM32_SRC_PLLSAI2_R (STM32_SRC_PLLSAI2_Q + 1) +#define STM32_SRC_PLLSAI2_DIVR (STM32_SRC_PLLSAI2_R + 1) + +/** @brief RCC_CCIPR register offset */ +#define CCIPR_REG 0x88 +#define CCIPR2_REG 0x9C + +/** @brief RCC_BDCR register offset */ +#define BDCR_REG 0x90 + +/** @brief RCC_CFGRx register offset */ +#define CFGR_REG 0x08 + +/** @brief Device domain clocks selection helpers */ +/** CCIPR devices */ +#define USART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR_REG) +#define USART2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 2, CCIPR_REG) +#define USART3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 4, CCIPR_REG) +#define UART4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 6, CCIPR_REG) +#define UART5_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR_REG) +#define LPUART1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 10, CCIPR_REG) +#define I2C1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR_REG) +#define I2C2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 14, CCIPR_REG) +#define I2C3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 16, CCIPR_REG) +#define LPTIM1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 18, CCIPR_REG) +#define LPTIM2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR_REG) +#define LPTIM3_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 22, CCIPR_REG) +#define FDCAN_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CCIPR_REG) +#define CLK48_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 26, CCIPR_REG) +#define ADC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 28, CCIPR_REG) +/** CCIPR2 devices */ +#define I2C4_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 0, CCIPR2_REG) +#define DFSDM_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 2, CCIPR2_REG) +#define ADFSDM_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 3, CCIPR2_REG) +#define SAI1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 5, CCIPR2_REG) +#define SAI2_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, CCIPR2_REG) +#define SDMMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 14, CCIPR2_REG) +#define OSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR2_REG) + +/** BDCR devices */ +#define RTC_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 8, BDCR_REG) +/** CFGR devices */ +#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 0xF, 24, CFGR_REG) +#define MCO1_PRE(val) STM32_DT_CLOCK_SELECT((val), 0x7, 28, CFGR_REG) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L5_CLOCK_H_ */ diff --git a/samples/drivers/i2s/output/boards/nucleo_l552ze_q.conf b/samples/drivers/i2s/output/boards/nucleo_l552ze_q.conf new file mode 100644 index 0000000000000..4f3f73a1e06a5 --- /dev/null +++ b/samples/drivers/i2s/output/boards/nucleo_l552ze_q.conf @@ -0,0 +1 @@ +CONFIG_HEAP_MEM_POOL_SIZE=4192 diff --git a/samples/drivers/i2s/output/boards/nucleo_l552ze_q.overlay b/samples/drivers/i2s/output/boards/nucleo_l552ze_q.overlay new file mode 100644 index 0000000000000..26dfeaa298a7b --- /dev/null +++ b/samples/drivers/i2s/output/boards/nucleo_l552ze_q.overlay @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Mario Paja + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2s-tx = &sai1_a; + }; +}; + +/* 44.117KHz (0.03% Error) */ +&pllsai1 { + div-m = <1>; + mul-n = <48>; + div-r = <2>; + div-q = <2>; + div-p = <17>; + clocks = <&clk_msi>; + status = "okay"; +}; + +&sai1_a { + pinctrl-0 = <&sai1_mclk_a_pe2 &sai1_sd_a_pe6 + &sai1_fs_a_pe4 &sai1_sck_a_pe5>; + pinctrl-names = "default"; + status = "okay"; + mclk-enable; + mclk-divider = "div-256"; + dma-names = "tx"; +}; + +&dmamux1 { + status = "okay"; +}; + +&dma1 { + status = "okay"; +};