drivers: i2s: Add support for I2S stm32

STM32 I2S driver implementation. It has been designed in the most
generic way possible, with the possibility of using it in master/slave
and rx/tx mode. Currenty it has been tested for master rx mode only
using the microphone on ArgonKey board.

The configuration file permits to compile it for STM32F4xx product
family only, but it should be easy to extend it also for other
families.

It supports all 5 STM32F4xx I2S controllers (I2S 1/4/5 on APB2 and
I2S 2/3 on APB1).
It makes uses of the available DMA channels for rx/tx streams.

The clock source can be selected among one of the following two choices:

  - PLLI2S pll, with possibility to configure PLLM/PLLN/PLLR
  - HSE/HSI clock

Interrupt is triggered only in case of errors (FRM/OVR/UDR).

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2018-06-14 09:27:46 +02:00 committed by Carles Cufí
commit 7b82e9f2d0
4 changed files with 1375 additions and 0 deletions

View file

@ -4,3 +4,4 @@ zephyr_library_sources(i2s_common.c)
zephyr_library_sources_ifdef(CONFIG_I2S_SAM_SSC i2s_sam_ssc.c)
zephyr_library_sources_ifdef(CONFIG_I2S_CAVS i2s_cavs.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE i2s_handlers.c)
zephyr_library_sources_ifdef(CONFIG_I2S_STM32 i2s_ll_stm32.c)

98
drivers/i2s/Kconfig.stm32 Normal file
View file

@ -0,0 +1,98 @@
# Kconfig - STM32 I2S driver configuration options
#
# Copyright (c) 2018 STMicroelectronics
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig I2S_STM32
bool "STM32 MCU I2S controller driver"
depends on I2S && SOC_SERIES_STM32F4X
select DMA
default n
help
Enable I2S support on the STM32 family of processors.
(Tested on the STM32F4 series)
if I2S_STM32
config I2S_STM32_RX_BLOCK_COUNT
int "RX queue length"
default 4
config I2S_STM32_TX_BLOCK_COUNT
int "TX queue length"
default 4
config I2S_STM32_USE_PLLI2S_ENABLE
bool "Enable usage of PLL"
default n
help
Enable it if I2S clock should be provided by the PLLI2S.
If not enabled the clock will be provided by HSI/HSE.
config I2S_STM32_PLLI2S_PLLM
int "Division factor for PLLI2S VCO input clock"
depends on I2S_STM32_USE_PLLI2S_ENABLE
default 8
range 2 63
help
Division factor for the audio PLL (PLLI2S) VCO input clock.
PLLM factor should be selected to ensure that the VCO
input frequency ranges from 1 to 2 MHz. It is recommended
to select a frequency of 2 MHz to limit PLL jitter.
Allowed values: 2-63
config I2S_STM32_PLLI2S_PLLN
int "Multiplier factor for PLLI2S VCO output clock"
depends on I2S_STM32_USE_PLLI2S_ENABLE
default 56
range 50 432
help
Multiply factor for the audio PLL (PLLI2S) VCO output clock.
PLLN factor should be selected to ensure that the VCO
output frequency ranges from 100 to 432 MHz.
Allowed values: 50-432
config I2S_STM32_PLLI2S_PLLR
int "Division factor for I2S clock"
depends on I2S_STM32_USE_PLLI2S_ENABLE
default 7
range 2 7
help
Division factor for the I2S clock.
PLLR factor should be selected to ensure that the I2S clock
frequency is less than or equal to 192MHz.
Allowed values: 2-7
config I2S_1
bool "I2S port 1"
default n
help
Enable I2S controller port 1.
config I2S_2
bool "I2S port 2"
default n
help
Enable I2S controller port 2.
config I2S_3
bool "I2S port 3"
default n
help
Enable I2S controller port 3.
config I2S_4
bool "I2S port 4"
default n
help
Enable I2S controller port 4.
config I2S_5
bool "I2S port 5"
default n
help
Enable I2S controller port 5.
endif # I2S_STM32

1147
drivers/i2s/i2s_ll_stm32.c Normal file

File diff suppressed because it is too large Load diff

129
drivers/i2s/i2s_ll_stm32.h Normal file
View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2018 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _STM32_I2S_H_
#define _STM32_I2S_H_
#ifdef CONFIG_I2S_STM32_USE_PLLI2S_ENABLE
#if defined(RCC_CFGR_I2SSRC)
/* single selector for the I2S clock source (SEL_1 == SEL_2) */
#define CLK_SEL_1 LL_RCC_I2S1_CLKSOURCE_PLLI2S
#define CLK_SEL_2 LL_RCC_I2S1_CLKSOURCE_PLLI2S
#else
#if defined(RCC_DCKCFGR_I2SSRC)
/* single selector for the I2S clock source (SEL_1 == SEL_2) */
#define CLK_SEL_1 LL_RCC_I2S1_CLKSOURCE_PLL
#define CLK_SEL_2 LL_RCC_I2S1_CLKSOURCE_PLL
#else
#if defined(RCC_DCKCFGR_I2S1SRC) && defined(RCC_DCKCFGR_I2S2SRC)
/* double selector for the I2S clock source (SEL_1 != SEL_2) */
#define CLK_SEL_1 LL_RCC_I2S1_CLKSOURCE_PLLI2S
#define CLK_SEL_2 LL_RCC_I2S2_CLKSOURCE_PLLI2S
#endif /* RCC_DCKCFGR_I2S1SRC && RCC_DCKCFGR_I2S2SRC */
#endif /* RCC_DCKCFGR_I2SSRC */
#endif /* RCC_CFGR_I2SSRC */
#else
#if defined(RCC_CFGR_I2SSRC)
/* single selector for the I2S clock source (SEL_1 == SEL_2) */
#define CLK_SEL_1 LL_RCC_I2S1_CLKSOURCE_PIN
#define CLK_SEL_2 LL_RCC_I2S1_CLKSOURCE_PIN
#else
#if defined(RCC_DCKCFGR_I2SSRC)
/* single selector for the I2S clock source (SEL_1 == SEL_2) */
#define CLK_SEL_1 LL_RCC_I2S1_CLKSOURCE_PLLSRC
#define CLK_SEL_2 LL_RCC_I2S1_CLKSOURCE_PLLSRC
#else
#if defined(RCC_DCKCFGR_I2S1SRC) && defined(RCC_DCKCFGR_I2S2SRC)
/* double selector for the I2S clock source (SEL_1 != SEL_2) */
#define CLK_SEL_1 LL_RCC_I2S1_CLKSOURCE_PLLSRC
#define CLK_SEL_2 LL_RCC_I2S2_CLKSOURCE_PLLSRC
#endif /* RCC_DCKCFGR_I2S1SRC && RCC_DCKCFGR_I2S2SRC */
#endif /* RCC_DCKCFGR_I2SSRC */
#endif /* RCC_CFGR_I2SSRC */
#endif /* CONFIG_I2S_STM32_USE_PLLI2S_ENABLE */
#ifdef CONFIG_SOC_SERIES_STM32F4X
#define I2S1_DMA_NAME CONFIG_DMA_2_NAME
#define I2S1_DMA_CHAN_RX 2
#define I2S1_DMA_SLOT_RX 3
#define I2S1_DMA_CHAN_TX 3
#define I2S1_DMA_SLOT_TX 3
#define I2S2_DMA_NAME CONFIG_DMA_1_NAME
#define I2S2_DMA_CHAN_RX 3
#define I2S2_DMA_SLOT_RX 0
#define I2S2_DMA_CHAN_TX 4
#define I2S2_DMA_SLOT_TX 0
#define I2S3_DMA_NAME CONFIG_DMA_1_NAME
#define I2S3_DMA_CHAN_RX 0
#define I2S3_DMA_SLOT_RX 0
#define I2S3_DMA_CHAN_TX 5
#define I2S3_DMA_SLOT_TX 0
#define I2S4_DMA_NAME CONFIG_DMA_2_NAME
#define I2S4_DMA_CHAN_RX 0
#define I2S4_DMA_SLOT_RX 4
#define I2S4_DMA_CHAN_TX 1
#define I2S4_DMA_SLOT_TX 4
#define I2S5_DMA_NAME CONFIG_DMA_2_NAME
#define I2S5_DMA_CHAN_RX 5
#define I2S5_DMA_SLOT_RX 7
#define I2S5_DMA_CHAN_TX 6
#define I2S5_DMA_SLOT_TX 7
#endif
#define DEV_CFG(dev) \
(const struct i2s_stm32_cfg * const)((dev)->config->config_info)
#define DEV_DATA(dev) \
((struct i2s_stm32_data *const)(dev)->driver_data)
struct queue_item {
void *mem_block;
size_t size;
};
/* Minimal ring buffer implementation */
struct ring_buf {
struct queue_item *buf;
u16_t len;
u16_t head;
u16_t tail;
};
/* Device constant configuration parameters */
struct i2s_stm32_cfg {
SPI_TypeDef *i2s;
struct stm32_pclken pclken;
u32_t i2s_clk_sel;
void (*irq_config)(struct device *dev);
};
struct stream {
s32_t state;
struct k_sem sem;
u32_t dma_channel;
struct dma_config dma_cfg;
struct i2s_config cfg;
struct ring_buf mem_block_queue;
void *mem_block;
bool last_block;
bool master;
int (*stream_start)(struct stream *, struct device *dev);
void (*stream_disable)(struct stream *, struct device *dev);
void (*queue_drop)(struct stream *);
};
/* Device run time data */
struct i2s_stm32_data {
struct device *dev_dma;
const char *dma_name;
struct stream rx;
struct stream tx;
};
#endif /* _STM32_I2S_H_ */