Commit 7b82e9f2 authored by Armando Visconti's avatar Armando Visconti Committed by Carles Cufi
Browse files

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: default avatarArmando Visconti <armando.visconti@st.com>
parent 31f2e81e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
# 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 −0

File added.

Preview size limit exceeded, changes collapsed.

+129 −0
Original line number Diff line number Diff line
/*
 * 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_ */