From 5065849ab6e5a8325d77b2dd4f093a3e7b8fbaec Mon Sep 17 00:00:00 2001 From: Alan Carvalho de Assis Date: Thu, 22 Jun 2023 14:05:15 -0300 Subject: [PATCH] esp32s3/i2s: Add initial support to I2S peripheral The I2S peripherals are now supported for both receiving and transmitting controllers. --- arch/xtensa/src/esp32s3/Kconfig | 246 +- arch/xtensa/src/esp32s3/Make.defs | 4 + arch/xtensa/src/esp32s3/esp32s3_i2s.c | 3138 +++++++++++++++++ arch/xtensa/src/esp32s3/esp32s3_i2s.h | 75 + .../xtensa/src/esp32s3/hardware/esp32s3_i2s.h | 1888 ++++++++++ 5 files changed, 5349 insertions(+), 2 deletions(-) create mode 100644 arch/xtensa/src/esp32s3/esp32s3_i2s.c create mode 100644 arch/xtensa/src/esp32s3/esp32s3_i2s.h create mode 100644 arch/xtensa/src/esp32s3/hardware/esp32s3_i2s.h diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig index 42760604ff8..9aabec31d28 100644 --- a/arch/xtensa/src/esp32s3/Kconfig +++ b/arch/xtensa/src/esp32s3/Kconfig @@ -276,6 +276,248 @@ config ESP32S3_I2C bool default n +config ESP32S3_I2S + bool "I2S" + select I2S + ---help--- + See the Board Selection menu to configure the pins used by I2S. + +if ESP32S3_I2S + +config ESP32S3_I2S0 + bool "I2S 0" + default n + select ESP32S3_DMA + select ESP32S3_GPIO_IRQ + select SCHED_HPWORK + +if ESP32S3_I2S0 + +config ESP32S3_I2S0_RX + bool "Enable I2S receiver" + default y + ---help--- + Enable I2S receiver (port 0) + +config ESP32S3_I2S0_TX + bool "Enable I2S transmitter" + default y + ---help--- + Enable I2S transmitter (port 0) + +choice + prompt "I2S0 role" + default ESP32S3_I2S0_ROLE_MASTER + ---help--- + Selects the operation role of the I2S0. + +config ESP32S3_I2S0_ROLE_MASTER + bool "Master" + +config ESP32S3_I2S0_ROLE_SLAVE + bool "Slave" + +endchoice + +choice + prompt "Bit width" + default ESP32S3_I2S0_DATA_BIT_WIDTH_16BIT + ---help--- + Selects the valid data bits per sample. + Note that this option may be overwritten by the audio + according to the bit width of the file being played + +config ESP32S3_I2S0_DATA_BIT_WIDTH_8BIT + bool "8 bits" + +config ESP32S3_I2S0_DATA_BIT_WIDTH_16BIT + bool "16 bits" + +config ESP32S3_I2S0_DATA_BIT_WIDTH_24BIT + bool "24 bits" + +config ESP32S3_I2S0_DATA_BIT_WIDTH_32BIT + bool "32 bits" + +endchoice + +config ESP32S3_I2S0_DATA_BIT_WIDTH + int + default 8 if ESP32S3_I2S0_DATA_BIT_WIDTH_8BIT + default 16 if ESP32S3_I2S0_DATA_BIT_WIDTH_16BIT + default 24 if ESP32S3_I2S0_DATA_BIT_WIDTH_24BIT + default 32 if ESP32S3_I2S0_DATA_BIT_WIDTH_32BIT + +config ESP32S3_I2S0_SAMPLE_RATE + int "I2S0 sample rate" + default 44100 + range 8000 48000 + ---help--- + Selects the sample rate. + Note that this option may be overwritten by the audio + according to the bit width of the file being played + +config ESP32S3_I2S0_BCLKPIN + int "I2S0 BCLK pin" + default 4 + range 0 33 if ESP32S3_I2S0_ROLE_MASTER + range 0 39 if ESP32S3_I2S0_ROLE_SLAVE + +config ESP32S3_I2S0_WSPIN + int "I2S0 WS pin" + default 5 + range 0 33 if ESP32S3_I2S0_ROLE_MASTER + range 0 39 if ESP32S3_I2S0_ROLE_SLAVE + +config ESP32S3_I2S0_DINPIN + int "I2S0 DIN pin" + depends on ESP32S3_I2S0_RX + default 19 + range 0 39 + +config ESP32S3_I2S0_DOUTPIN + int "I2S0 DOUT pin" + depends on ESP32S3_I2S0_TX + default 18 + range 0 33 + +config ESP32S3_I2S0_MCLK + bool "Enable I2S Master Clock" + depends on ESP32S3_I2S0_ROLE_MASTER + default n + ---help--- + Enable I2S master clock + +config ESP32S3_I2S0_MCLKPIN + int "I2S MCLK pin" + depends on ESP32S3_I2S0_MCLK + default 0 + range 0 39 + +endif #ESP32S3_I2S0 + +config ESP32S3_I2S1 + bool "I2S 1" + default n + select ESP32S3_DMA + select ESP32S3_GPIO_IRQ + select SCHED_HPWORK + +if ESP32S3_I2S1 + +config ESP32S3_I2S1_RX + bool "Enable I2S receiver" + default y + ---help--- + Enable I2S receiver (port 1) + +config ESP32S3_I2S1_TX + bool "Enable I2S transmitter" + default y + ---help--- + Enable I2S transmitter (port 1) + +choice + prompt "I2S1 role" + default ESP32S3_I2S1_ROLE_MASTER + ---help--- + Selects the operation role of the I2S1. + +config ESP32S3_I2S1_ROLE_MASTER + bool "Master" + +config ESP32S3_I2S1_ROLE_SLAVE + bool "Slave" + +endchoice + +choice + prompt "Bit width" + default ESP32S3_I2S1_DATA_BIT_WIDTH_16BIT + ---help--- + Selects the valid data bits per sample. + Note that this option may be overwritten by the audio + according to the bit width of the file being played + +config ESP32S3_I2S1_DATA_BIT_WIDTH_8BIT + bool "8 bits" + +config ESP32S3_I2S1_DATA_BIT_WIDTH_16BIT + bool "16 bits" + +config ESP32S3_I2S1_DATA_BIT_WIDTH_24BIT + bool "24 bits" + +config ESP32S3_I2S1_DATA_BIT_WIDTH_32BIT + bool "32 bits" + +endchoice + +config ESP32S3_I2S1_DATA_BIT_WIDTH + int + default 8 if ESP32S3_I2S1_DATA_BIT_WIDTH_8BIT + default 16 if ESP32S3_I2S1_DATA_BIT_WIDTH_16BIT + default 24 if ESP32S3_I2S1_DATA_BIT_WIDTH_24BIT + default 32 if ESP32S3_I2S1_DATA_BIT_WIDTH_32BIT + +config ESP32S3_I2S1_SAMPLE_RATE + int "I2S1 sample rate" + default 44100 + range 8000 48000 + ---help--- + Selects the sample rate. + Note that this option may be overwritten by the audio + according to the bit width of the file being played + +config ESP32S3_I2S1_BCLKPIN + int "I2S1 BCLK pin" + default 22 + range 0 33 if ESP32S3_I2S1_ROLE_MASTER + range 0 39 if ESP32S3_I2S1_ROLE_SLAVE + +config ESP32S3_I2S1_WSPIN + int "I2S1 WS pin" + default 23 + range 0 33 if ESP32S3_I2S1_ROLE_MASTER + range 0 39 if ESP32S3_I2S1_ROLE_SLAVE + +config ESP32S3_I2S1_DINPIN + int "I2S1 DIN pin" + depends on ESP32S3_I2S1_RX + default 26 + range 0 39 + +config ESP32S3_I2S1_DOUTPIN + int "I2S1 DOUT pin" + depends on ESP32S3_I2S1_TX + default 25 + range 0 33 + +config ESP32S3_I2S1_MCLK + bool "Enable I2S Master Clock" + depends on ESP32S3_I2S1_ROLE_MASTER + default n + ---help--- + Enable I2S master clock + +config ESP32S3_I2S1_MCLKPIN + int "I2S MCLK pin" + depends on ESP32S3_I2S1_MCLK + default 1 + range 0 39 + +endif #ESP32S3_I2S1 + +config I2S_DMADESC_NUM + int "I2S DMA maximum number of descriptors" + default 2 + ---help--- + Configure the maximum number of out-link/in-link descriptors to + be chained for a I2S DMA transfer. + +endif #ESP32S3_I2S + + config ESP32S3_SPI bool default n @@ -966,7 +1208,7 @@ choice ESP32S3_POWER_SAVE_MODE BB are turned off in order to reduce power consumption. Station can keep connection with AP in modem-sleep mode. Modem-sleep mode includes minimum and maximum power-saving modes. - + In minimum power-saving mode, station wakes up every DTIM to receive beacon. Broadcast data will not be lost because it is transmitted after DTIM. However, it cannot save much more power if DTIM is short for DTIM is determined by AP. @@ -983,7 +1225,7 @@ choice ESP32S3_POWER_SAVE_MODE config ESP32S3_POWER_SAVE_NONE bool "No power save" - + config ESP32S3_POWER_SAVE_MIN_MODEM bool "Minimum modem power saving." diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs index 4cd5063c68c..775edc822c8 100644 --- a/arch/xtensa/src/esp32s3/Make.defs +++ b/arch/xtensa/src/esp32s3/Make.defs @@ -105,6 +105,10 @@ ifeq ($(CONFIG_ESP32S3_I2C),y) CHIP_CSRCS += esp32s3_i2c.c endif +ifeq ($(CONFIG_ESP32S3_I2S),y) +CHIP_CSRCS += esp32s3_i2s.c +endif + ifeq ($(CONFIG_ESP32S3_SPI),y) ifeq ($(CONFIG_ESP32S3_SPI_IO_SPI),y) CHIP_CSRCS += esp32s3_spi.c diff --git a/arch/xtensa/src/esp32s3/esp32s3_i2s.c b/arch/xtensa/src/esp32s3/esp32s3_i2s.c new file mode 100644 index 00000000000..94ed92acdbd --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_i2s.c @@ -0,0 +1,3138 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_i2s.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_ESP32S3_I2S + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "esp32s3_i2s.h" +#include "esp32s3_gpio.h" +#include "esp32s3_irq.h" +#include "esp32s3_dma.h" + +#include "xtensa.h" +#include "hardware/esp32s3_gpio_sigmap.h" +#include "hardware/esp32s3_system.h" +#include "hardware/esp32s3_i2s.h" +#include "hardware/esp32s3_soc.h" +#include "hardware/esp32s3_iomux.h" +#include "hardware/esp32s3_pinmap.h" +#include "hardware/esp32s3_dma.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* I2S DMA RX/TX description number */ + +#define I2S_DMADESC_NUM (CONFIG_I2S_DMADESC_NUM) + +/* I2S Clock */ + +#define I2S_LL_BASE_CLK (2 * APB_CLK_FREQ) +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) + +/* I2S DMA channel number */ + +#define I2S_DMA_CHANNEL_MAX (2) + +#ifdef CONFIG_ESP32S3_I2S0_TX +# define I2S0_TX_ENABLED 1 +# define I2S_HAVE_TX 1 +#else +# define I2S0_TX_ENABLED 0 +#endif + +#ifdef CONFIG_ESP32S3_I2S0_RX +# define I2S0_RX_ENABLED 1 +# define I2S_HAVE_RX 1 +#else +# define I2S0_RX_ENABLED 0 +#endif + +#ifdef CONFIG_ESP32S3_I2S1_TX +# define I2S1_TX_ENABLED 1 +# define I2S_HAVE_TX 1 +#else +# define I2S1_TX_ENABLED 0 +#endif + +#ifdef CONFIG_ESP32S3_I2S1_RX +# define I2S1_RX_ENABLED 1 +# define I2S_HAVE_RX 1 +#else +# define I2S1_RX_ENABLED 0 +#endif + +#ifndef ALIGN_UP +# define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#endif + +/* Debug ********************************************************************/ + +#ifdef CONFIG_DEBUG_I2S_INFO +# define CONFIG_ESP32S3_I2S_DUMPBUFFERS +#else +# undef CONFIG_ESP32S3_I2S_DUMPBUFFERS +#endif + +#ifndef CONFIG_ESP32S3_I2S_MAXINFLIGHT +# define CONFIG_ESP32S3_I2S_MAXINFLIGHT 4 +#endif + +#define I2S_GPIO_UNUSED -1 /* For signals which are not used */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Role of the I2S port */ + +typedef enum +{ + I2S_ROLE_MASTER, /* I2S controller master role, bclk and ws signal will be set to output */ + I2S_ROLE_SLAVE /* I2S controller slave role, bclk and ws signal will be set to input */ +} i2s_role_t; + +/* Data width of the I2S channel */ + +typedef enum +{ + I2S_DATA_BIT_WIDTH_8BIT = 8, /* I2S channel data bit-width: 8 */ + I2S_DATA_BIT_WIDTH_16BIT = 16, /* I2S channel data bit-width: 16 */ + I2S_DATA_BIT_WIDTH_24BIT = 24, /* I2S channel data bit-width: 24 */ + I2S_DATA_BIT_WIDTH_32BIT = 32, /* I2S channel data bit-width: 32 */ +} i2s_data_bit_width_t; + +/* Multiplier of MCLK to sample rate */ + +typedef enum +{ + I2S_MCLK_MULTIPLE_128 = 128, /* mclk = sample_rate * 128 */ + I2S_MCLK_MULTIPLE_256 = 256, /* mclk = sample_rate * 256 */ + I2S_MCLK_MULTIPLE_384 = 384, /* mclk = sample_rate * 384 */ + I2S_MCLK_MULTIPLE_512 = 512, /* mclk = sample_rate * 512 */ +} i2s_mclk_multiple_t; + +/* I2S Clock Source */ + +typedef enum +{ + I2S_XTAL_CLK = 0, + I2S_PLL_D2_CLK, + I2S_PLL_F160M_CLK, + I2S_MCLK_IN, +} i2s_clk_src_t; + +/* I2S Audio Standard Mode */ + +typedef enum +{ + I2S_TDM_PHILIPS = 0, + I2S_TDM_MSB, + I2S_TDM_PCM, + I2S_PDM, +} i2s_audio_mode_t; + +/* Role of the I2S port */ + +typedef enum +{ + I2S_RX, /* I2S controller receiver (RX) */ + I2S_TX /* I2S controller transmitter (TX) */ +} i2s_dir_t; + +/* I2S Device hardware configuration */ + +struct esp32s3_i2s_config_s +{ + uint32_t port; /* I2S port */ + uint32_t role; /* I2S port role (master or slave) */ + uint8_t data_width; /* I2S sample data width */ + uint32_t rate; /* I2S sample-rate */ + uint32_t total_slot; /* Total slot number */ + + bool tx_en; /* Is TX enabled? */ + bool rx_en; /* Is RX enabled? */ + int8_t mclk_pin; /* MCLK pin, output */ + + int tx_clk_src; /* Select the I2S TX source clock */ + int rx_clk_src; /* Select the I2S TX source clock */ + + /* BCLK pin, input in slave role, output in master role */ + + int8_t bclk_pin; + + /* WS pin, input in slave role, output in master role */ + + int8_t ws_pin; + + int8_t dout_pin; /* DATA pin, output */ + int8_t din_pin; /* DATA pin, input */ + + uint32_t bclk_in_insig; /* RX channel BCK signal (slave mode) index */ + uint32_t bclk_in_outsig; /* RX channel BCK signal (master mode) index */ + uint32_t bclk_out_insig; /* TX channel BCK signal (slave mode) index */ + uint32_t bclk_out_outsig; /* TX channel BCK signal (master mode) index */ + uint32_t ws_in_insig; /* RX channel WS signal (slave mode) index */ + uint32_t ws_in_outsig; /* RX channel WS signal (master mode) index */ + uint32_t ws_out_insig; /* TX channel WS signal (slave mode) index */ + uint32_t ws_out_outsig; /* TX channel WS signal (master mode) index */ + uint32_t din_insig; /* RX channel Data Input signal index */ + uint32_t dout_outsig; /* TX channel Data Output signal index */ + uint32_t mclk_out_sig; /* Master clock output index */ + + uint8_t audio_std_mode; /* Select audio standard (i2s_audio_mode_t) */ + + /* WS signal polarity, set true to enable high level first */ + + bool ws_pol; +}; + +struct esp32s3_buffer_s +{ + struct esp32s3_buffer_s *flink; /* Supports a singly linked list */ + + /* The associated DMA in/outlink */ + + struct esp32s3_dmadesc_s dma_link[I2S_DMADESC_NUM]; + + i2s_callback_t callback; /* DMA completion callback */ + uint32_t timeout; /* Timeout value of the DMA transfers */ + void *arg; /* Callback's argument */ + struct ap_buffer_s *apb; /* The audio buffer */ + uint8_t *buf; /* The DMA's descriptor buffer */ + uint32_t nbytes; /* The DMA's descriptor buffer size */ + int result; /* The result of the transfer */ +}; + +/* Internal buffer must be aligned to the bytes_per_sample. Sometimes, + * however, the audio buffer is not aligned and additional bytes must + * be copied to be inserted on the next buffer. This structure keeps + * track of the bytes that were not written to the internal buffer yet. + */ + +struct esp32s3_buffer_carry_s +{ + uint32_t value; + size_t bytes; +}; + +/* This structure describes the state of one receiver or transmitter + * transport. + */ + +struct esp32s3_transport_s +{ + sq_queue_t pend; /* A queue of pending transfers */ + sq_queue_t act; /* A queue of active transfers */ + sq_queue_t done; /* A queue of completed transfers */ + struct work_s work; /* Supports worker thread operations */ + + /* Bytes to be written at the beginning of the next DMA buffer */ + + struct esp32s3_buffer_carry_s carry; +}; + +/* The state of the one I2S peripheral */ + +struct esp32s3_i2s_s +{ + struct i2s_dev_s dev; /* Externally visible I2S interface */ + mutex_t lock; /* Ensures mutually exclusive access */ + uint8_t cpu; /* CPU ID */ + spinlock_t slock; /* Device specific lock. */ + + /* Port configuration */ + + const struct esp32s3_i2s_config_s *config; + + uint32_t mclk_freq; /* I2S actual master clock */ + uint32_t mclk_multiple; /* The multiple of mclk to the sample rate */ + uint32_t channels; /* Audio channels (1:mono or 2:stereo) */ + uint32_t rate; /* I2S actual configured sample-rate */ + uint32_t data_width; /* I2S actual configured data_width */ + uint32_t dma_channel; /* I2S DMA channel being used */ + +#ifdef I2S_HAVE_TX + struct esp32s3_transport_s tx; /* TX transport state */ + + int tx_irq; /* TX IRQ */ + bool tx_started; /* TX channel started */ +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + struct esp32s3_transport_s rx; /* RX transport state */ + + int rx_irq; /* RX IRQ */ + bool rx_started; /* RX channel started */ +#endif /* I2S_HAVE_RX */ + + /* Pre-allocated pool of buffer containers */ + + sem_t bufsem; /* Buffer wait semaphore */ + struct esp32s3_buffer_s *bf_freelist; /* A list a free buffer containers */ + struct esp32s3_buffer_s containers[CONFIG_ESP32S3_I2S_MAXINFLIGHT]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register helpers */ + +#ifdef CONFIG_ESP32S3_I2S_DUMPBUFFERS +# define i2s_dump_buffer(m,b,s) lib_dumpbuffer(m,b,s) +#else +# define i2s_dump_buffer(m,b,s) +#endif + +/* Buffer container helpers */ + +static struct esp32s3_buffer_s * + i2s_buf_allocate(struct esp32s3_i2s_s *priv); +static void i2s_buf_free(struct esp32s3_i2s_s *priv, + struct esp32s3_buffer_s *bfcontainer); +static int i2s_buf_initialize(struct esp32s3_i2s_s *priv); + +/* DMA support */ + +#ifdef I2S_HAVE_TX +static IRAM_ATTR int i2s_txdma_setup(struct esp32s3_i2s_s *priv, + struct esp32s3_buffer_s *bfcontainer); +static void i2s_tx_worker(void *arg); +static void i2s_tx_schedule(struct esp32s3_i2s_s *priv, + struct esp32s3_dmadesc_s *outlink); +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX +static IRAM_ATTR int i2s_rxdma_setup(struct esp32s3_i2s_s *priv, + struct esp32s3_buffer_s *bfcontainer); +static void i2s_rx_worker(void *arg); +static void i2s_rx_schedule(struct esp32s3_i2s_s *priv, + struct esp32s3_dmadesc_s *outlink); +#endif /* I2S_HAVE_RX */ + +/* I2S methods (and close friends) */ + +static uint32_t i2s_set_datawidth(struct esp32s3_i2s_s *priv); +static uint32_t i2s_set_clock(struct esp32s3_i2s_s *priv); +static uint32_t i2s_getmclkfrequency(struct i2s_dev_s *dev); +static uint32_t i2s_setmclkfrequency(struct i2s_dev_s *dev, + uint32_t frequency); +static int i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg); + +#ifdef I2S_HAVE_TX +static void i2s_tx_channel_start(struct esp32s3_i2s_s *priv); +static void i2s_tx_channel_stop(struct esp32s3_i2s_s *priv); +static int i2s_txchannels(struct i2s_dev_s *dev, uint8_t channels); +static uint32_t i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate); +static uint32_t i2s_txdatawidth(struct i2s_dev_s *dev, int bits); +static int i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, + uint32_t timeout); +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX +static void i2s_rx_channel_start(struct esp32s3_i2s_s *priv); +static void i2s_rx_channel_stop(struct esp32s3_i2s_s *priv); +static int i2s_rxchannels(struct i2s_dev_s *dev, uint8_t channels); +static uint32_t i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate); +static uint32_t i2s_rxdatawidth(struct i2s_dev_s *dev, int bits); +static int i2s_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, + uint32_t timeout); +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct i2s_ops_s g_i2sops = +{ +#ifdef I2S_HAVE_TX + .i2s_txchannels = i2s_txchannels, + .i2s_txsamplerate = i2s_txsamplerate, + .i2s_txdatawidth = i2s_txdatawidth, + .i2s_send = i2s_send, +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + .i2s_rxchannels = i2s_rxchannels, + .i2s_rxsamplerate = i2s_rxsamplerate, + .i2s_rxdatawidth = i2s_rxdatawidth, + .i2s_receive = i2s_receive, +#endif /* I2S_HAVE_RX */ + + .i2s_ioctl = i2s_ioctl, + .i2s_getmclkfrequency = i2s_getmclkfrequency, + .i2s_setmclkfrequency = i2s_setmclkfrequency, +}; + +#ifdef CONFIG_ESP32S3_I2S0 +static const struct esp32s3_i2s_config_s esp32s3_i2s0_config = +{ + .port = 0, +#ifdef CONFIG_ESP32S3_I2S0_ROLE_MASTER + .role = I2S_ROLE_MASTER, +#else + .role = I2S_ROLE_SLAVE, +#endif /* CONFIG_ESP32S3_I2S0_ROLE_MASTER */ + .data_width = CONFIG_ESP32S3_I2S0_DATA_BIT_WIDTH, + .rate = CONFIG_ESP32S3_I2S0_SAMPLE_RATE, + .total_slot = 2, + .tx_en = I2S0_TX_ENABLED, + .rx_en = I2S0_RX_ENABLED, + .tx_clk_src = I2S_PLL_D2_CLK, + .rx_clk_src = I2S_PLL_D2_CLK, +#ifdef CONFIG_ESP32S3_I2S0_MCLK + .mclk_pin = CONFIG_ESP32S3_I2S0_MCLKPIN, +#else + .mclk_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESP32S3_I2S0_MCLK */ + .bclk_pin = CONFIG_ESP32S3_I2S0_BCLKPIN, + .ws_pin = CONFIG_ESP32S3_I2S0_WSPIN, +#ifdef CONFIG_ESP32S3_I2S0_DOUTPIN + .dout_pin = CONFIG_ESP32S3_I2S0_DOUTPIN, +#else + .dout_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESP32S3_I2S0_DOUTPIN */ +#ifdef CONFIG_ESP32S3_I2S0_DINPIN + .din_pin = CONFIG_ESP32S3_I2S0_DINPIN, +#else + .din_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESP32S3_I2S0_DINPIN */ + .bclk_in_insig = I2S0I_BCK_IN_IDX, + .bclk_in_outsig = I2S0I_BCK_OUT_IDX, + .bclk_out_insig = I2S0O_BCK_IN_IDX, + .bclk_out_outsig = I2S0O_BCK_OUT_IDX, + .ws_in_insig = I2S0I_WS_IN_IDX, + .ws_in_outsig = I2S0I_WS_OUT_IDX, + .ws_out_insig = I2S0O_WS_IN_IDX, + .ws_out_outsig = I2S0O_WS_OUT_IDX, + .din_insig = I2S0I_SD_IN_IDX, + .dout_outsig = I2S0O_SD_OUT_IDX, + .mclk_out_sig = I2S0_MCLK_OUT_IDX, + .audio_std_mode = I2S_TDM_PHILIPS, +}; + +static struct esp32s3_i2s_s esp32s3_i2s0_priv = +{ + .dev = + { + .ops = &g_i2sops, + }, + .lock = NXMUTEX_INITIALIZER, + .config = &esp32s3_i2s0_config, + .bufsem = SEM_INITIALIZER(0), +}; +#endif /* CONFIG_ESP32S3_I2S0 */ + +#ifdef CONFIG_ESP32S3_I2S1 +static const struct esp32s3_i2s_config_s esp32s3_i2s1_config = +{ + .port = 1, +#ifdef CONFIG_ESP32S3_I2S1_ROLE_MASTER + .role = I2S_ROLE_MASTER, +#else + .role = I2S_ROLE_SLAVE, +#endif /* CONFIG_ESP32S3_I2S1_ROLE_MASTER */ + .data_width = CONFIG_ESP32S3_I2S1_DATA_BIT_WIDTH, + .rate = CONFIG_ESP32S3_I2S1_SAMPLE_RATE, + .total_slot = 2, + .tx_en = I2S1_TX_ENABLED, + .rx_en = I2S1_RX_ENABLED, + .tx_clk_src = I2S_PLL_D2_CLK, + .tx_clk_src = I2S_PLL_D2_CLK, +#ifdef CONFIG_ESP32S3_I2S1_MCLK + .mclk_pin = CONFIG_ESP32S3_I2S1_MCLKPIN, +#else + .mclk_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESP32S3_I2S1_MCLK */ + .bclk_pin = CONFIG_ESP32S3_I2S1_BCLKPIN, + .ws_pin = CONFIG_ESP32S3_I2S1_WSPIN, +#ifdef CONFIG_ESP32S3_I2S1_DOUTPIN + .dout_pin = CONFIG_ESP32S3_I2S1_DOUTPIN, +#else + .dout_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESP32S3_I2S1_DOUTPIN */ +#ifdef CONFIG_ESP32S3_I2S1_DINPIN + .din_pin = CONFIG_ESP32S3_I2S1_DINPIN, +#else + .din_pin = I2S_GPIO_UNUSED, +#endif /* CONFIG_ESP32S3_I2S1_DINPIN */ + .bclk_in_insig = I2S1I_BCK_IN_IDX, + .bclk_in_outsig = I2S1I_BCK_OUT_IDX, + .bclk_out_insig = I2S1O_BCK_IN_IDX, + .bclk_out_outsig = I2S1O_BCK_OUT_IDX, + .ws_in_insig = I2S1I_WS_IN_IDX, + .ws_in_outsig = I2S1I_WS_OUT_IDX, + .ws_out_insig = I2S1O_WS_IN_IDX, + .ws_out_outsig = I2S1O_WS_OUT_IDX, + .din_insig = I2S1I_SD_IN_IDX, + .dout_outsig = I2S1O_SD_OUT_IDX, + .mclk_out_sig = I2S1_MCLK_OUT_IDX, + .audio_std_mode = I2S_TDM_PHILIPS, +}; + +static struct esp32s3_i2s_s esp32s3_i2s1_priv = +{ + .dev = + { + .ops = &g_i2sops, + }, + .lock = NXMUTEX_INITIALIZER, + .config = &esp32s3_i2s1_config, + .bufsem = SEM_INITIALIZER(0), +}; +#endif /* CONFIG_ESP32S3_I2S1 */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: i2s_buf_allocate + * + * Description: + * Allocate a buffer container by removing the one at the head of the + * free list + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * A non-NULL pointer to the allocate buffer container on success; NULL if + * there are no available buffer containers. + * + * Assumptions: + * The caller does NOT have exclusive access to the I2S state structure. + * That would result in a deadlock! + * + ****************************************************************************/ + +static struct esp32s3_buffer_s *i2s_buf_allocate(struct esp32s3_i2s_s *priv) +{ + struct esp32s3_buffer_s *bfcontainer; + irqstate_t flags; + int ret; + + /* Set aside a buffer container. By doing this, we guarantee that we will + * have at least one free buffer container. + */ + + ret = nxsem_wait_uninterruptible(&priv->bufsem); + if (ret < 0) + { + return NULL; + } + + /* Get the buffer from the head of the free list */ + + flags = spin_lock_irqsave(&priv->slock); + bfcontainer = priv->bf_freelist; + DEBUGASSERT(bfcontainer); + + /* Unlink the buffer from the freelist */ + + priv->bf_freelist = bfcontainer->flink; + spin_unlock_irqrestore(&priv->slock, flags); + return bfcontainer; +} + +/**************************************************************************** + * Name: i2s_buf_free + * + * Description: + * Free buffer container by adding it to the head of the free list + * + * Input Parameters: + * priv - Initialized I2S device structure. + * bfcontainer - The buffer container to be freed + * + * Returned Value: + * None + * + * Assumptions: + * The caller has exclusive access to the I2S state structure + * + ****************************************************************************/ + +static void i2s_buf_free(struct esp32s3_i2s_s *priv, + struct esp32s3_buffer_s *bfcontainer) +{ + irqstate_t flags; + + /* Put the buffer container back on the free list (circbuf) */ + + flags = spin_lock_irqsave(&priv->slock); + + bfcontainer->apb = NULL; + bfcontainer->buf = NULL; + bfcontainer->nbytes = 0; + bfcontainer->flink = priv->bf_freelist; + priv->bf_freelist = bfcontainer; + + spin_unlock_irqrestore(&priv->slock, flags); + + /* Wake up any threads waiting for a buffer container */ + + nxsem_post(&priv->bufsem); +} + +/**************************************************************************** + * Name: i2s_buf_initialize + * + * Description: + * Initialize the buffer container allocator by adding all of the + * pre-allocated buffer containers to the free list + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + * Assumptions: + * Called early in I2S initialization so that there are no issues with + * concurrency. + * + ****************************************************************************/ + +static int i2s_buf_initialize(struct esp32s3_i2s_s *priv) +{ +#ifdef I2S_HAVE_TX + priv->tx.carry.bytes = 0; + priv->tx.carry.value = 0; +#endif /* I2S_HAVE_TX */ + + priv->bf_freelist = NULL; + for (int i = 0; i < CONFIG_ESP32S3_I2S_MAXINFLIGHT; i++) + { + i2s_buf_free(priv, &priv->containers[i]); + } + + return OK; +} + +/**************************************************************************** + * Name: i2s_txdma_start + * + * Description: + * Initiate the next TX DMA transfer. The DMA outlink was previously bound + * so it is safe to start the next DMA transfer at interrupt level. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int IRAM_ATTR i2s_txdma_start(struct esp32s3_i2s_s *priv) +{ + struct esp32s3_buffer_s *bfcontainer; + + /* If there is already an active transmission in progress, then bail + * returning success. + */ + + if (!sq_empty(&priv->tx.act)) + { + return OK; + } + + /* If there are no pending transfer, then bail returning success */ + + if (sq_empty(&priv->tx.pend)) + { + return OK; + } + + /* Start transmission if no data is already being transmitted */ + + bfcontainer = (struct esp32s3_buffer_s *)sq_remfirst(&priv->tx.pend); + + esp32s3_dma_load(bfcontainer->dma_link, priv->dma_channel, I2S_TX); + esp32s3_dma_enable(priv->dma_channel, I2S_TX); + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), 0, I2S_TX_START); + + sq_addlast((sq_entry_t *)bfcontainer, &priv->tx.act); + + return OK; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxdma_start + * + * Description: + * Initiate the next RX DMA transfer. Assuming the DMA inlink is already + * bound, it's safe to start the next DMA transfer in an interrupt context. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rxdma_start(struct esp32s3_i2s_s *priv) +{ + struct esp32s3_buffer_s *bfcontainer; + size_t eof_nbytes; + + /* If there is already an active transmission in progress, then bail + * returning success. + */ + + if (!sq_empty(&priv->rx.act)) + { + return OK; + } + + /* If there are no pending transfer, then bail returning success */ + + if (sq_empty(&priv->rx.pend)) + { + return OK; + } + + bfcontainer = (struct esp32s3_buffer_s *)sq_remfirst(&priv->rx.pend); + + /* If there isn't already an active transmission in progress, + * then start it. + */ + + eof_nbytes = MIN(bfcontainer->nbytes, ESP32S3_DMA_BUFLEN_MAX); + + modifyreg32(I2S_RXEOF_NUM_REG(priv->config->port), I2S_RX_EOF_NUM_M, + FIELD_TO_VALUE(I2S_RX_EOF_NUM, eof_nbytes)); + + esp32s3_dma_load(bfcontainer->dma_link, priv->dma_channel, I2S_RX); + esp32s3_dma_enable(priv->dma_channel, I2S_RX); + + modifyreg32(I2S_RX_CONF_REG(priv->config->port), 0, I2S_RX_START); + + sq_addlast((sq_entry_t *)bfcontainer, &priv->rx.act); + + return OK; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_txdma_setup + * + * Description: + * Setup the next TX DMA transfer + * + * Input Parameters: + * priv - Initialized I2S device structure. + * bfcontainer - The buffer container to be set up + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static IRAM_ATTR int i2s_txdma_setup(struct esp32s3_i2s_s *priv, + struct esp32s3_buffer_s *bfcontainer) +{ + int ret = OK; + size_t carry_size; + uint32_t bytes_queued; + uint32_t data_copied; + struct ap_buffer_s *apb; + struct esp32s3_dmadesc_s *outlink; + apb_samp_t samp_size; + irqstate_t flags; + uint8_t *buf; + uint8_t padding; + uint8_t *samp; + + DEBUGASSERT(bfcontainer && bfcontainer->apb); + + apb = bfcontainer->apb; + outlink = bfcontainer->dma_link; + + /* Get the transfer information, accounting for any data offset */ + + const apb_samp_t bytes_per_sample = priv->data_width / 8; + samp = &apb->samp[apb->curbyte]; + samp_size = (apb->nbytes - apb->curbyte) + priv->tx.carry.bytes; + carry_size = samp_size % bytes_per_sample; + + /* Allocate the current audio buffer considering the remaining bytes + * carried from the last upper half audio buffer. + */ + + bfcontainer->buf = calloc(bfcontainer->nbytes, 1); + if (bfcontainer->buf == NULL) + { + i2serr("Failed to allocate the DMA internal buffer " + "[%" PRIu32 " bytes]", bfcontainer->nbytes); + return -ENOMEM; + } + + data_copied = 0; + buf = bfcontainer->buf; + + /* Copy the remaining bytes from the last audio buffer to the current + * audio buffer. The remaining bytes are part of a sample that was split + * between the last and the current audio buffer. Also, copy the bytes + * from that split sample that are on the current buffer to the internal + * buffer. + */ + + if (priv->tx.carry.bytes) + { + memcpy(buf, &priv->tx.carry.value, priv->tx.carry.bytes); + buf += priv->tx.carry.bytes; + data_copied += priv->tx.carry.bytes; + memcpy(buf, samp, (bytes_per_sample - priv->tx.carry.bytes)); + buf += (bytes_per_sample - priv->tx.carry.bytes); + samp += (bytes_per_sample - priv->tx.carry.bytes); + data_copied += (bytes_per_sample - priv->tx.carry.bytes); + } + + /* Copy the upper half buffer to the internal buffer considering that + * the current upper half buffer may not contain a complete sample at + * the end of the buffer (and those bytes needs to be carried to the + * next audio buffer). + */ + + memcpy(buf, samp, samp_size - (data_copied + carry_size)); + buf += samp_size - (data_copied + carry_size); + samp += samp_size - (data_copied + carry_size); + data_copied += samp_size - (data_copied + carry_size); + + /* If the audio buffer's size is not a multiple of the sample size, + * it's necessary to carry the remaining bytes that are part of what + * would be the last sample on this buffer. These bytes will then be + * saved and inserted at the beginning of the next DMA buffer to + * rebuild the sample correctly. + */ + + priv->tx.carry.bytes = carry_size; + + if (priv->tx.carry.bytes) + { + memcpy((uint8_t *)&priv->tx.carry.value, samp, priv->tx.carry.bytes); + } + + /* Release our reference on the audio buffer. This may very likely + * cause the audio buffer to be freed. + */ + + apb_free(bfcontainer->apb); + + /* Configure DMA stream */ + + bytes_queued = esp32s3_dma_setup(outlink, I2S_DMADESC_NUM, + bfcontainer->buf, + bfcontainer->nbytes, I2S_TX); + + if (bytes_queued != bfcontainer->nbytes) + { + i2serr("Failed to enqueue I2S buffer " + "(%" PRIu32 " bytes of %" PRIu32 ")\n", + bytes_queued, bfcontainer->nbytes); + return -bytes_queued; + } + + flags = spin_lock_irqsave(&priv->slock); + + /* Add the buffer container to the end of the TX pending queue */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->tx.pend); + + /* Trigger DMA transfer if no transmission is in progress */ + + ret = i2s_txdma_start(priv); + + spin_unlock_irqrestore(&priv->slock, flags); + + return ret; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxdma_setup + * + * Description: + * Setup the next RX DMA transfer + * + * Input Parameters: + * priv - Initialized I2S device structure. + * bfcontainer - The buffer container to be set up + * + * Returned Value: + * OK on success; a negated errno value on failure + * + * Assumptions: + * Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rxdma_setup(struct esp32s3_i2s_s *priv, + struct esp32s3_buffer_s *bfcontainer) +{ + int ret = OK; + struct esp32s3_dmadesc_s *inlink; + uint32_t bytes_queued; + irqstate_t flags; + + DEBUGASSERT(bfcontainer && bfcontainer->apb); + + inlink = bfcontainer->dma_link; + + /* Configure DMA stream */ + + bytes_queued = esp32s3_dma_setup(inlink, I2S_DMADESC_NUM, + bfcontainer->apb->samp, + bfcontainer->nbytes, I2S_RX); + + if (bytes_queued != bfcontainer->nbytes) + { + i2serr("Failed to enqueue I2S buffer " + "(%" PRIu32 " bytes of %" PRIu32 ")\n", + bytes_queued, bfcontainer->nbytes); + return -bytes_queued; + } + + flags = spin_lock_irqsave(&priv->slock); + + /* Add the buffer container to the end of the RX pending queue */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->rx.pend); + + /* Trigger DMA transfer if no transmission is in progress */ + + ret = i2s_rxdma_start(priv); + + spin_unlock_irqrestore(&priv->slock, flags); + + return ret; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_schedule + * + * Description: + * An TX DMA completion has occurred. Schedule processing on + * the working thread. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * outlink - DMA outlink descriptor that triggered the interrupt. + * + * Returned Value: + * None + * + * Assumptions: + * - Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void IRAM_ATTR i2s_tx_schedule(struct esp32s3_i2s_s *priv, + struct esp32s3_dmadesc_s *outlink) +{ + struct esp32s3_buffer_s *bfcontainer; + struct esp32s3_dmadesc_s *bfdesc; + int ret; + + /* Upon entry, the transfer(s) that just completed are the ones in the + * priv->tx.act queue. + */ + + /* Move all entries from the tx.act queue to the tx.done queue */ + + if (!sq_empty(&priv->tx.act)) + { + /* Remove the next buffer container from the tx.act list */ + + bfcontainer = (struct esp32s3_buffer_s *)sq_peek(&priv->tx.act); + + /* Check if the DMA descriptor that generated an EOF interrupt is the + * last descriptor of the current buffer container's DMA outlink. + * REVISIT: what to do if we miss syncronization and the descriptor + * that generated the interrupt is different from the expected (the + * oldest of the list containing active transmissions)? + */ + + /* Find the last descriptor of the current buffer container */ + + bfdesc = bfcontainer->dma_link; + while (!(bfdesc->ctrl & ESP32S3_DMA_CTRL_EOF)) + { + DEBUGASSERT(bfdesc->next); + bfdesc = bfdesc->next; + } + + if (bfdesc == outlink) + { + sq_remfirst(&priv->tx.act); + + /* Report the result of the transfer */ + + bfcontainer->result = OK; + + /* Add the completed buffer container to the tail of the tx.done + * queue + */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->tx.done); + + /* Check if the DMA is IDLE */ + + if (sq_empty(&priv->tx.act)) + { + /* Then start the next DMA. */ + + i2s_txdma_start(priv); + } + } + + /* If the worker has completed running, then reschedule the working + * thread. + */ + + if (work_available(&priv->tx.work)) + { + /* Schedule the TX DMA done processing to occur on the worker + * thread. + */ + + ret = work_queue(HPWORK, &priv->tx.work, i2s_tx_worker, priv, 0); + if (ret != 0) + { + i2serr("ERROR: Failed to queue TX work: %d\n", ret); + } + } + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_schedule + * + * Description: + * An RX DMA completion has occurred. Schedule processing on + * the working thread. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * inlink - DMA inlink descriptor that triggered the interrupt. + * + * Returned Value: + * None + * + * Assumptions: + * - Interrupts are disabled + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_schedule(struct esp32s3_i2s_s *priv, + struct esp32s3_dmadesc_s *inlink) +{ + struct esp32s3_buffer_s *bfcontainer; + struct esp32s3_dmadesc_s *bfdesc; + int ret; + + /* Upon entry, the transfer(s) that just completed are the ones in the + * priv->rx.act queue. + */ + + /* Move all entries from the rx.act queue to the rx.done queue */ + + if (!sq_empty(&priv->rx.act)) + { + /* Remove the next buffer container from the rx.act list */ + + bfcontainer = (struct esp32s3_buffer_s *)sq_peek(&priv->rx.act); + + /* Find the last descriptor of the current buffer container */ + + bfdesc = bfcontainer->dma_link; + + while (bfdesc->next != NULL && + (bfdesc->next->ctrl & ESP32S3_DMA_CTRL_EOF)) + { + bfdesc = bfdesc->next; + } + + if (bfdesc == inlink) + { + sq_remfirst(&priv->rx.act); + + /* Report the result of the transfer */ + + bfcontainer->result = OK; + + /* Add the completed buffer container to the tail of the rx.done + * queue + */ + + sq_addlast((sq_entry_t *)bfcontainer, &priv->rx.done); + + /* Check if the DMA is IDLE */ + + if (sq_empty(&priv->rx.act)) + { + /* Then start the next DMA. */ + + i2s_rxdma_start(priv); + } + } + + /* If the worker has completed running, then reschedule the working + * thread. + */ + + if (work_available(&priv->rx.work)) + { + /* Schedule the RX DMA done processing to occur on the worker + * thread. + */ + + ret = work_queue(HPWORK, &priv->rx.work, i2s_rx_worker, priv, 0); + if (ret != 0) + { + i2serr("ERROR: Failed to queue RX work: %d\n", ret); + } + } + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_worker + * + * Description: + * TX transfer done worker + * + * Input Parameters: + * arg - the I2S device instance cast to void* + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void i2s_tx_worker(void *arg) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)arg; + struct esp32s3_buffer_s *bfcontainer; + irqstate_t flags; + + DEBUGASSERT(priv); + + /* When the transfer was started, the active buffer containers were removed + * from the tx.pend queue and saved in the tx.act queue. We get here when + * the DMA is finished. + * + * In any case, the buffer containers in tx.act will be moved to the end + * of the tx.done queue and tx.act will be emptied before this worker is + * started. + * + */ + + i2sinfo("tx.act.head=%p tx.done.head=%p\n", + priv->tx.act.head, priv->tx.done.head); + + /* Process each buffer in the tx.done queue */ + + while (sq_peek(&priv->tx.done) != NULL) + { + /* Remove the buffer container from the tx.done queue. NOTE that + * interrupts must be disabled to do this because the tx.done queue is + * also modified from the interrupt level. + */ + + flags = spin_lock_irqsave(&priv->slock); + bfcontainer = (struct esp32s3_buffer_s *)sq_remfirst(&priv->tx.done); + spin_unlock_irqrestore(&priv->slock, flags); + + /* Perform the TX transfer done callback */ + + DEBUGASSERT(bfcontainer && bfcontainer->callback); + bfcontainer->callback(&priv->dev, bfcontainer->apb, + bfcontainer->arg, bfcontainer->result); + + /* Release the internal buffer used by the DMA outlink */ + + free(bfcontainer->buf); + + /* And release the buffer container */ + + i2s_buf_free(priv, bfcontainer); + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_worker + * + * Description: + * RX transfer done worker + * + * Input Parameters: + * arg - the I2S device instance cast to void* + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_worker(void *arg) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)arg; + struct esp32s3_buffer_s *bfcontainer; + struct esp32s3_dmadesc_s *dmadesc; + irqstate_t flags; + + DEBUGASSERT(priv); + + /* When the transfer was started, the active buffer containers were removed + * from the rx.pend queue and saved in the rx.act queue. We get here when + * the DMA is finished. + * + * In any case, the buffer containers in rx.act will be moved to the end + * of the rx.done queue and rx.act will be emptied before this worker is + * started. + * + */ + + i2sinfo("rx.act.head=%p rx.done.head=%p\n", + priv->rx.act.head, priv->rx.done.head); + + /* Process each buffer in the rx.done queue */ + + while (sq_peek(&priv->rx.done) != NULL) + { + /* Remove the buffer container from the rx.done queue. NOTE that + * interrupts must be disabled to do this because the rx.done queue is + * also modified from the interrupt level. + */ + + flags = spin_lock_irqsave(&priv->slock); + bfcontainer = (struct esp32s3_buffer_s *)sq_remfirst(&priv->rx.done); + spin_unlock_irqrestore(&priv->slock, flags); + + dmadesc = bfcontainer->dma_link; + + bfcontainer->apb->nbytes = 0; + + while (dmadesc != NULL && (dmadesc->ctrl & ESP32S3_DMA_CTRL_EOF)) + { + bfcontainer->apb->nbytes += + (dmadesc->ctrl >> ESP32S3_DMA_CTRL_DATALEN_S) & + ESP32S3_DMA_CTRL_DATALEN_V; + dmadesc = dmadesc->next; + } + + /* Perform the RX transfer done callback */ + + DEBUGASSERT(bfcontainer && bfcontainer->callback); + + /* Release the internal buffer used by the DMA inlink */ + + bfcontainer->callback(&priv->dev, bfcontainer->apb, + bfcontainer->arg, bfcontainer->result); + + /* Release our reference on the audio buffer. This may very likely + * cause the audio buffer to be freed. + */ + + apb_free(bfcontainer->apb); + + /* And release the buffer container */ + + i2s_buf_free(priv, bfcontainer); + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_configure + * + * Description: + * Configure I2S + * + * Input Parameters: + * priv - Partially initialized I2S device structure. This function + * will complete the I2S specific portions of the initialization + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void i2s_configure(struct esp32s3_i2s_s *priv) +{ + uint32_t tx_conf = 0; + uint32_t tx_conf1 = 0; + uint32_t rx_conf = 0; + uint32_t rx_conf1 = 0; + + /* Set peripheral clock and clear reset */ + + if (priv->config->port == ESP32S3_I2S0) + { + modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, SYSTEM_I2S0_CLK_EN); + modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, SYSTEM_I2S0_RST); + modifyreg32(SYSTEM_PERIP_RST_EN0_REG, SYSTEM_I2S0_RST, 0); + } + else + { + modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, SYSTEM_I2S1_CLK_EN); + modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, SYSTEM_I2S1_RST); + modifyreg32(SYSTEM_PERIP_RST_EN0_REG, SYSTEM_I2S1_RST, 0); + } + + if (!(getreg32(I2S_TX_CLKM_CONF_REG(priv->config->port)) & I2S_CLK_EN)) + { + i2sinfo("Enabling I2S clock...\n"); + modifyreg32(I2S_TX_CLKM_CONF_REG(priv->config->port), 0, I2S_CLK_EN); + } + + /* Configure multiplexed pins as connected on the board */ + + /* TODO: check for loopback mode */ + + /* Enable TX channel */ + + if (priv->config->dout_pin != I2S_GPIO_UNUSED) + { + /* If TX channel is used, enable the clock source */ + + if (!(getreg32(I2S_TX_CLKM_CONF_REG(priv->config->port)) & + I2S_TX_CLK_ACTIVE)) + { + i2sinfo("Activating I2S TX clock...\n"); + modifyreg32(I2S_TX_CLKM_CONF_REG(priv->config->port), + I2S_TX_CLK_SEL_M, + FIELD_TO_VALUE(I2S_TX_CLK_SEL, 2)); + modifyreg32(I2S_TX_CLKM_CONF_REG(priv->config->port), 0, + I2S_TX_CLK_ACTIVE); + } + + esp32s3_gpiowrite(priv->config->dout_pin, 1); + esp32s3_configgpio(priv->config->dout_pin, OUTPUT_FUNCTION_2); + esp32s3_gpio_matrix_out(priv->config->dout_pin, + priv->config->dout_outsig, 0, 0); + } + + /* Enable RX channel */ + + if (priv->config->din_pin != I2S_GPIO_UNUSED) + { + /* If RX channel is used, enable the clock source */ + + if (!(getreg32(I2S_RX_CLKM_CONF_REG(priv->config->port)) & + I2S_RX_CLK_ACTIVE)) + { + i2sinfo("Activating I2S TX clock...\n"); + modifyreg32(I2S_RX_CLKM_CONF_REG(priv->config->port), + I2S_RX_CLK_SEL_M, + FIELD_TO_VALUE(I2S_RX_CLK_SEL, 2)); + modifyreg32(I2S_RX_CLKM_CONF_REG(priv->config->port), 0, + I2S_RX_CLK_ACTIVE); + } + + esp32s3_configgpio(priv->config->din_pin, INPUT_FUNCTION_2); + esp32s3_gpio_matrix_in(priv->config->din_pin, + priv->config->din_insig, 0); + } + + if (priv->config->role == I2S_ROLE_SLAVE) + { + if (priv->config->tx_en && !priv->config->rx_en) + { + /* For "tx + slave" mode, select TX signal index for ws and bck */ + + esp32s3_gpiowrite(priv->config->ws_pin, 1); + esp32s3_configgpio(priv->config->ws_pin, INPUT_FUNCTION_2); + esp32s3_gpio_matrix_in(priv->config->ws_pin, + priv->config->ws_out_insig, 0); + + esp32s3_gpiowrite(priv->config->bclk_pin, 1); + esp32s3_configgpio(priv->config->bclk_pin, INPUT_FUNCTION_2); + esp32s3_gpio_matrix_in(priv->config->bclk_pin, + priv->config->bclk_out_insig, 0); + } + else + { + /* For "tx + rx + slave" or "rx + slave" mode, select RX signal + * index for ws and bck. + */ + + esp32s3_gpiowrite(priv->config->ws_pin, 1); + esp32s3_configgpio(priv->config->ws_pin, INPUT_FUNCTION_2); + esp32s3_gpio_matrix_in(priv->config->ws_pin, + priv->config->ws_in_insig, 0); + + esp32s3_gpiowrite(priv->config->bclk_pin, 1); + esp32s3_configgpio(priv->config->bclk_pin, INPUT_FUNCTION_2); + esp32s3_gpio_matrix_in(priv->config->bclk_pin, + priv->config->bclk_in_insig, 0); + } + } + else + { + /* Considering master role for the I2S port */ + + /* Set MCLK pin */ + + if (priv->config->mclk_pin != I2S_GPIO_UNUSED) + { + i2sinfo("Configuring GPIO%" PRIu8 " to output master clock\n", + priv->config->mclk_pin); + + esp32s3_gpiowrite(priv->config->mclk_pin, 1); + esp32s3_configgpio(priv->config->mclk_pin, OUTPUT_FUNCTION_2); + esp32s3_gpio_matrix_out(priv->config->mclk_pin, + priv->config->mclk_out_sig, 0, 0); + } + + if (priv->config->rx_en && !priv->config->tx_en) + { + /* For "rx + master" mode, select RX signal index for ws and bck */ + + esp32s3_gpiowrite(priv->config->ws_pin, 1); + esp32s3_configgpio(priv->config->ws_pin, OUTPUT_FUNCTION_2); + esp32s3_gpio_matrix_out(priv->config->ws_pin, + priv->config->ws_in_outsig, 0, 0); + + esp32s3_gpiowrite(priv->config->bclk_pin, 1); + esp32s3_configgpio(priv->config->bclk_pin, OUTPUT_FUNCTION_2); + esp32s3_gpio_matrix_out(priv->config->bclk_pin, + priv->config->bclk_in_outsig, 0, 0); + } + else + { + /* For "tx + rx + master" or "tx + master" mode, select TX signal + * index for ws and bck. + */ + + esp32s3_gpiowrite(priv->config->ws_pin, 1); + esp32s3_configgpio(priv->config->ws_pin, OUTPUT_FUNCTION_2); + esp32s3_gpio_matrix_out(priv->config->ws_pin, + priv->config->ws_out_outsig, 0, 0); + + esp32s3_gpiowrite(priv->config->bclk_pin, 1); + esp32s3_configgpio(priv->config->bclk_pin, OUTPUT_FUNCTION_2); + esp32s3_gpio_matrix_out(priv->config->bclk_pin, + priv->config->bclk_out_outsig, 0, 0); + } + } + + /* Share BCLK and WS if in full-duplex mode */ + + if (priv->config->tx_en && priv->config->rx_en) + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), 0, I2S_SIG_LOOPBACK); + } + else + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), I2S_SIG_LOOPBACK, 0); + } + + /* Configure the TX module */ + + if (priv->config->tx_en) + { + /* Reset I2S TX module */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), 0, I2S_TX_RESET); + modifyreg32(I2S_TX_CONF_REG(priv->config->port), I2S_TX_RESET, 0); + + /* Enable/disable I2S TX slave mode */ + + if (priv->config->role == I2S_ROLE_SLAVE) + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + 0, I2S_TX_SLAVE_MOD); + } + else + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + I2S_TX_SLAVE_MOD, 0); + } + + /* Configure TX chan bit, audio data bit and mono mode. + * On ESP32-S3, sample_bit should equals to data_bit. + */ + + /* Set TX data width */ + + priv->data_width = priv->config->data_width; + i2s_set_datawidth(priv); + + /* Set channel mode control */ + + if (priv->config->audio_std_mode <= I2S_TDM_PCM) + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), I2S_TX_TDM_EN_M, + I2S_TX_TDM_EN); + + if (priv->config->audio_std_mode == I2S_TDM_PHILIPS) + { + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_MSB_SHIFT_M, I2S_TX_MSB_SHIFT); + } + else + { + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_MSB_SHIFT, 0); + } + } + else + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), I2S_TX_PDM_EN_M, + I2S_TX_PDM_EN); + } + + /* Set the default level of WS */ + + if (priv->config->ws_pol == 1) + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), 0, + I2S_TX_WS_IDLE_POL); + } + else + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + I2S_TX_WS_IDLE_POL, 0); + } + + /* The default value for the master clock frequency (MCLK frequency) + * can be set from the sample rate multiplied by a fixed value, known + * as MCLK multiplier. This multiplier, however, should be divisible + * by the number of bytes from a sample, i.e, for 24 bits, the + * multiplier should be divisible by 3. NOTE: the MCLK frequency can + * be adjusted on runtime, so this value remains valid only if the + * upper half does not implement the `i2s_setmclkfrequency` method. + */ + + if (priv->config->data_width == I2S_DATA_BIT_WIDTH_24BIT) + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_384; + } + else + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_256; + } + + i2s_setmclkfrequency((struct i2s_dev_s *)priv, (priv->config->rate * + priv->mclk_multiple)); + + priv->rate = priv->config->rate; + i2s_set_clock(priv); + } + + /* Configure the RX module */ + + if (priv->config->rx_en) + { + /* Reset I2S RX module */ + + modifyreg32(I2S_RX_CONF_REG(priv->config->port), 0, I2S_RX_RESET); + modifyreg32(I2S_RX_CONF_REG(priv->config->port), I2S_RX_RESET, 0); + + /* Enable/disable I2S RX slave mode */ + + if (priv->config->role == I2S_ROLE_SLAVE) + { + modifyreg32(I2S_RX_CONF_REG(priv->config->port), + 0, I2S_RX_SLAVE_MOD); + } + else + { + /* Since BCLK and WS are shared, only TX or RX can be master. In + * this case, force RX as slave to avoid conflict of clock signal. + */ + + if (priv->config->tx_en) + { + modifyreg32(I2S_RX_CONF_REG(priv->config->port), 0, + I2S_RX_SLAVE_MOD); + } + else + { + modifyreg32(I2S_RX_CONF_REG(priv->config->port), + I2S_RX_SLAVE_MOD, 0); + } + } + + /* Congfigure RX chan bit, audio data bit and mono mode. + * On ESP32, sample_bit should equals to data_bit. + */ + + /* Set RX data width */ + + priv->data_width = priv->config->data_width; + i2s_set_datawidth(priv); + + /* Set channel mode control */ + + if (priv->config->audio_std_mode <= I2S_TDM_PCM) + { + modifyreg32(I2S_RX_CONF_REG(priv->config->port), I2S_RX_TDM_EN_M, + I2S_RX_TDM_EN); + + if (priv->config->audio_std_mode == I2S_TDM_PHILIPS) + { + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_MSB_SHIFT_M, I2S_RX_MSB_SHIFT); + } + else + { + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_MSB_SHIFT, 0); + } + } + else + { + modifyreg32(I2S_RX_CONF_REG(priv->config->port), I2S_RX_PDM_EN_M, + I2S_RX_PDM_EN); + } + + /* Set I2S RX right channel first */ + + if (priv->config->ws_pol == 1) + { + modifyreg32(I2S_RX_CONF_REG(priv->config->port), 0, + I2S_RX_BIG_ENDIAN); + } + else + { + modifyreg32(I2S_RX_CONF_REG(priv->config->port), + I2S_RX_BIG_ENDIAN, 0); + } + + /* The default value for the master clock frequency (MCLK frequency) + * can be set from the sample rate multiplied by a fixed value, known + * as MCLK multiplier. This multiplier, however, should be divisible + * by the number of bytes from a sample, i.e, for 24 bits, the + * multiplier should be divisible by 3. NOTE: the MCLK frequency can + * be adjusted on runtime, so this value remains valid only if the + * upper half does not implement the `i2s_setmclkfrequency` method. + */ + + if (priv->config->data_width == I2S_DATA_BIT_WIDTH_24BIT) + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_384; + } + else + { + priv->mclk_multiple = I2S_MCLK_MULTIPLE_256; + } + + i2s_setmclkfrequency((struct i2s_dev_s *)priv, (priv->config->rate * + priv->mclk_multiple)); + + priv->rate = priv->config->rate; + i2s_set_clock(priv); + } +} + +/**************************************************************************** + * Name: i2s_set_datawidth + * + * Description: + * Set the I2S TX/RX data width. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * Returns the resulting data width + * + ****************************************************************************/ + +static uint32_t i2s_set_datawidth(struct esp32s3_i2s_s *priv) +{ +#ifdef I2S_HAVE_TX + if (priv->config->tx_en) + { + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_BITS_MOD_M, FIELD_TO_VALUE(I2S_TX_BITS_MOD, + priv->data_width - 1)); + + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_TDM_CHAN_BITS_M, + FIELD_TO_VALUE(I2S_TX_TDM_CHAN_BITS, + priv->data_width - 1)); + + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_HALF_SAMPLE_BITS_M, + FIELD_TO_VALUE(I2S_TX_HALF_SAMPLE_BITS, + priv->data_width - 1)); + + if (priv->config->audio_std_mode == I2S_TDM_PCM) + { + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_TDM_WS_WIDTH_M, + FIELD_TO_VALUE(I2S_TX_TDM_WS_WIDTH, 1)); + } + else + { + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_TDM_WS_WIDTH_M, + FIELD_TO_VALUE(I2S_TX_TDM_WS_WIDTH, + priv->data_width - 1)); + } + + /* Set I2S_TX_UPDATE bit to update configs. Cleared automatically */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + 0, I2S_TX_UPDATE); + } +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + if (priv->config->rx_en) + { + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_BITS_MOD_M, FIELD_TO_VALUE(I2S_RX_BITS_MOD, + priv->data_width - 1)); + + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_TDM_CHAN_BITS_M, + FIELD_TO_VALUE(I2S_RX_TDM_CHAN_BITS, + priv->data_width - 1)); + + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_HALF_SAMPLE_BITS_M, + FIELD_TO_VALUE(I2S_RX_HALF_SAMPLE_BITS, + priv->data_width - 1)); + + if (priv->config->audio_std_mode == I2S_TDM_PCM) + { + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_TDM_WS_WIDTH_M, + FIELD_TO_VALUE(I2S_RX_TDM_WS_WIDTH, + priv->data_width - 1)); + } + else + { + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_TDM_WS_WIDTH_M, + FIELD_TO_VALUE(I2S_RX_TDM_WS_WIDTH, 1)); + } + } +#endif /* I2S_HAVE_RX */ + + return priv->data_width; +} + +/**************************************************************************** + * Name: i2s_set_clock + * + * Description: + * Set the I2S TX sample rate by adjusting I2S clock. + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * Returns the resulting bitrate + * + ****************************************************************************/ + +static uint32_t i2s_set_clock(struct esp32s3_i2s_s *priv) +{ + uint32_t rate; + uint32_t bclk; + uint32_t mclk; + uint32_t sclk; + uint32_t mclk_div; + int denominator; + int numerator; + uint32_t regval; + uint32_t freq_diff; + uint16_t bclk_div; + + /* TODO: provide other clock support modes */ + + /* I2S module will using PLL_D2_CLK(160M) as source clock. */ + + sclk = I2S_LL_BASE_CLK; + + /* fmclk = bck_div * fbclk = fsclk / (mclk_div + b / a) + * mclk_div is the I2S clock divider's integral value + * b is the fraction clock divider's numerator value + * a is the fraction clock divider's denominator value + */ + + if (priv->config->role == I2S_ROLE_MASTER) + { + bclk = priv->rate * priv->config->total_slot * priv->data_width; + mclk = priv->mclk_freq; + bclk_div = mclk / bclk; + } + else + { + /* For slave mode, mclk >= bclk * 8, so fix bclk_div to 2 first */ + + bclk_div = 8; + bclk = priv->rate * priv->config->total_slot * priv->data_width; + mclk = bclk * bclk_div; + } + + /* Calculate the nearest integer value of the I2S clock divider */ + + mclk_div = sclk / mclk; + + i2sinfo("Clock division info: [sclk]%" PRIu32 " Hz [mdiv] %d " + "[mclk] %" PRIu32 " Hz [bdiv] %d [bclk] %" PRIu32 " Hz\n", + sclk, mclk_div, mclk, bclk_div, bclk); + + freq_diff = abs((int)sclk - (int)(mclk * mclk_div)); + + denominator = 1; + numerator = 0; + + if (freq_diff) + { + float decimal = freq_diff / (float)mclk; + + /* Carry bit if the decimal is greater than + * 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0 + */ + + if (decimal > 125.0f / 126.0f) + { + mclk_div++; + } + else + { + uint32_t min = UINT32_MAX; + + for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) + { + int b = (int)(a * (freq_diff / (double)mclk) + 0.5); + int ma = freq_diff * a; + int mb = mclk * b; + if (ma == mb) + { + denominator = a; + numerator = b; + break; + } + + if (abs((mb - ma)) < min) + { + denominator = a; + numerator = b; + min = abs(mb - ma); + } + } + } + } + + i2sinfo("Clock register: [mclk] %" PRIu32 " Hz [numerator] %d " + "[denominator] %d\n", mclk, numerator, denominator); + + /* Setup TX Clock */ + + regval = getreg32(I2S_TX_CLKM_CONF_REG(priv->config->port)); + regval &= ~I2S_TX_CLKM_DIV_NUM_M; + regval |= FIELD_TO_VALUE(I2S_TX_CLKM_DIV_NUM, mclk_div); + putreg32(regval, I2S_TX_CLKM_CONF_REG(priv->config->port)); + + regval = getreg32(I2S_TX_CLKM_DIV_CONF_REG(priv->config->port)); + regval &= ~(I2S_TX_CLKM_DIV_Z_M | I2S_TX_CLKM_DIV_Y_M | + I2S_TX_CLKM_DIV_X_M | I2S_TX_CLKM_DIV_YN1_M); + regval |= FIELD_TO_VALUE(I2S_TX_CLKM_DIV_Z, + numerator <= (denominator / 2) ? + numerator : (denominator - numerator)); + + regval |= FIELD_TO_VALUE(I2S_TX_CLKM_DIV_Y, + numerator <= (denominator / 2) ? + (denominator % numerator) : + (denominator % (denominator - numerator))); + + regval |= FIELD_TO_VALUE(I2S_TX_CLKM_DIV_X, + numerator <= (denominator / 2) ? + (int)(floor(denominator / numerator) - 1) : + (int)(floor(denominator / + (denominator - numerator))-1)); + + regval |= FIELD_TO_VALUE(I2S_TX_CLKM_DIV_YN1, + numerator <= (denominator / 2) ? + 0 : 1); + putreg32(regval, I2S_TX_CLKM_DIV_CONF_REG(priv->config->port)); + + /* Setup RX Clock */ + + regval = getreg32(I2S_RX_CLKM_CONF_REG(priv->config->port)); + regval &= ~I2S_RX_CLKM_DIV_NUM_M; + regval |= FIELD_TO_VALUE(I2S_RX_CLKM_DIV_NUM, mclk_div); + putreg32(regval, I2S_RX_CLKM_CONF_REG(priv->config->port)); + + regval = getreg32(I2S_RX_CLKM_DIV_CONF_REG(priv->config->port)); + regval &= ~(I2S_RX_CLKM_DIV_Z_M | I2S_RX_CLKM_DIV_Y_M | + I2S_RX_CLKM_DIV_X_M | I2S_RX_CLKM_DIV_YN1_M); + regval |= FIELD_TO_VALUE(I2S_RX_CLKM_DIV_Z, + numerator <= (denominator / 2) ? + numerator : (denominator - numerator)); + + regval |= FIELD_TO_VALUE(I2S_RX_CLKM_DIV_Y, + numerator <= (denominator / 2) ? + (denominator % numerator) : + (denominator % (denominator - numerator))); + + regval |= FIELD_TO_VALUE(I2S_RX_CLKM_DIV_X, + numerator <= (denominator / 2) ? + (int)(floor(denominator / numerator) - 1) : + (int)(floor(denominator / + (denominator - numerator))-1)); + + regval |= FIELD_TO_VALUE(I2S_RX_CLKM_DIV_YN1, + numerator <= (denominator / 2) ? + 0 : 1); + putreg32(regval, I2S_RX_CLKM_DIV_CONF_REG(priv->config->port)); + + /* Set I2S TX bck div num + * Note: I2S_TX/RX_BCK_DIV_NUM cannot be 1 + */ + +#ifdef I2S_HAVE_TX + modifyreg32(I2S_TX_CONF1_REG(priv->config->port), + I2S_TX_BCK_DIV_NUM_M, + FIELD_TO_VALUE(I2S_TX_BCK_DIV_NUM, bclk_div - 1)); + + /* Set I2S_TX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + 0, I2S_TX_UPDATE); +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + modifyreg32(I2S_RX_CONF1_REG(priv->config->port), + I2S_RX_BCK_DIV_NUM_M, + FIELD_TO_VALUE(I2S_RX_BCK_DIV_NUM, bclk_div - 1)); + + /* Set I2S_RX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + modifyreg32(I2S_RX_CONF_REG(priv->config->port), + 0, I2S_RX_UPDATE); +#endif /* I2S_HAVE_RX */ + + /* Returns the actual sample rate */ + + bclk = sclk / (float)((mclk_div + numerator / (float)denominator) * + bclk_div); + rate = bclk / (float)(priv->config->total_slot * priv->data_width); + + return rate; +} + +/**************************************************************************** + * Name: i2s_tx_channel_start + * + * Description: + * Start TX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void i2s_tx_channel_start(struct esp32s3_i2s_s *priv) +{ + if (priv->config->tx_en) + { + if (priv->tx_started) + { + i2swarn("TX channel of port %d was previously started\n", + priv->config->port); + return; + } + + /* Reset the DMA operation */ + + SET_GDMA_CH_BITS(DMA_OUT_CONF0_CH0_REG, priv->dma_channel, + DMA_OUT_RST_CH0_M); + CLR_GDMA_CH_BITS(DMA_OUT_CONF0_CH0_REG, priv->dma_channel, + DMA_OUT_RST_CH0_M); + CLR_GDMA_CH_BITS(DMA_OUT_CONF1_CH0_REG, priv->dma_channel, + DMA_OUT_CHECK_OWNER_CH0); + + /* Reset the TX channel */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), 0, I2S_TX_RESET); + modifyreg32(I2S_TX_CONF_REG(priv->config->port), I2S_TX_RESET, 0); + + /* Reset TX FIFO */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), 0, I2S_TX_FIFO_RESET); + modifyreg32(I2S_TX_CONF_REG(priv->config->port), I2S_TX_FIFO_RESET, 0); + + /* Set I2S_RX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), 0, I2S_TX_UPDATE); + + /* Enable DMA interrupt */ + + up_enable_irq(priv->tx_irq); + + SET_GDMA_CH_BITS(DMA_OUT_INT_ENA_CH0_REG, priv->dma_channel, + DMA_OUT_TOTAL_EOF_CH0_INT_ENA | + DMA_OUT_DSCR_ERR_CH0_INT_ENA); + + /* REVISIT: enable I2S interrupt and set the FIFO hung counter togit + * enable the `I2S_TX_HUNG_INT` and check for data timeout. + */ + + priv->tx_started = true; + + i2sinfo("Started TX channel of port %d\n", priv->config->port); + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_channel_start + * + * Description: + * Start RX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_channel_start(struct esp32s3_i2s_s *priv) +{ + if (priv->config->rx_en) + { + if (priv->rx_started) + { + i2swarn("RX channel of port %d was previously started\n", + priv->config->port); + return; + } + + /* Reset the DMA operation */ + + SET_GDMA_CH_BITS(DMA_IN_CONF0_CH0_REG, priv->dma_channel, + DMA_IN_RST_CH0_M); + CLR_GDMA_CH_BITS(DMA_IN_CONF0_CH0_REG, priv->dma_channel, + DMA_IN_RST_CH0_M); + + /* Reset the RX channel */ + + modifyreg32(I2S_RX_CONF_REG(priv->config->port), 0, I2S_RX_RESET); + modifyreg32(I2S_RX_CONF_REG(priv->config->port), I2S_RX_RESET, 0); + + /* Reset RX FIFO */ + + modifyreg32(I2S_RX_CONF_REG(priv->config->port), 0, I2S_RX_FIFO_RESET); + modifyreg32(I2S_RX_CONF_REG(priv->config->port), I2S_RX_FIFO_RESET, 0); + + /* Set I2S_RX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + modifyreg32(I2S_RX_CONF_REG(priv->config->port), 0, I2S_RX_UPDATE); + + /* Enable DMA interrupt */ + + up_enable_irq(priv->rx_irq); + + SET_GDMA_CH_BITS(DMA_IN_INT_ENA_CH0_REG, priv->dma_channel, + DMA_IN_SUC_EOF_CH0_INT_ENA); + + /* REVISIT: enable I2S interrupt and set the FIFO hung counter to + * enable the `I2S_RX_HUNG_INT` and check for data timeout. + */ + + priv->rx_started = true; + + i2sinfo("Started RX channel of port %d\n", priv->config->port); + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_channel_stop + * + * Description: + * Stop TX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static void i2s_tx_channel_stop(struct esp32s3_i2s_s *priv) +{ + if (priv->config->tx_en) + { + if (!priv->tx_started) + { + i2swarn("TX channel of port %d was previously stopped\n", + priv->config->port); + return; + } + + /* Stop TX channel */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), I2S_TX_START, 0); + + /* Stop outlink */ + + SET_GDMA_CH_BITS(DMA_OUT_LINK_CH0_REG, priv->dma_channel, + DMA_OUTLINK_STOP_CH0_M); + + /* Disable DMA interrupt */ + + CLR_GDMA_CH_BITS(DMA_OUT_INT_ENA_CH0_REG, priv->dma_channel, + DMA_OUT_EOF_CH0_INT_ENA); + + /* Disable DMA operation mode */ + + up_disable_irq(priv->tx_irq); + + priv->tx_started = false; + + i2sinfo("Stopped TX channel of port %d\n", priv->config->port); + } +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_channel_stop + * + * Description: + * Stop RX channel for the I2S port + * + * Input Parameters: + * priv - Initialized I2S device structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static void i2s_rx_channel_stop(struct esp32s3_i2s_s *priv) +{ + if (priv->config->rx_en) + { + if (!priv->rx_started) + { + i2swarn("RX channel of port %d was previously stopped\n", + priv->config->port); + return; + } + + /* Stop RX channel */ + + modifyreg32(I2S_RX_CONF_REG(priv->config->port), I2S_RX_START, 0); + + /* Stop outlink */ + + SET_GDMA_CH_BITS(DMA_IN_LINK_CH0_REG, priv->dma_channel, + DMA_INLINK_STOP_CH0_M); + + /* Disable DMA interrupt */ + + CLR_GDMA_CH_BITS(DMA_IN_INT_ENA_CH0_REG, priv->dma_channel, + DMA_IN_SUC_EOF_CH0_INT_ENA); + + /* Disable DMA operation mode */ + + up_disable_irq(priv->rx_irq); + + priv->rx_started = false; + + i2sinfo("Stopped RX channel of port %d\n", priv->config->port); + } +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_tx_interrupt + * + * Description: + * Common I2S DMA interrupt handler + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info + * arg - I2S controller private data + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int IRAM_ATTR i2s_tx_interrupt(int irq, void *context, void *arg) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)arg; + struct esp32s3_dmadesc_s *cur = NULL; + + uint32_t status = GET_GDMA_CH_REG(DMA_OUT_INT_ST_CH0_REG, + priv->dma_channel); + + SET_GDMA_CH_REG(DMA_OUT_INT_CLR_CH0_REG, priv->dma_channel, + UINT32_MAX); + + if (priv->config->tx_en) + { + if (status & DMA_OUT_TOTAL_EOF_CH0_INT_ST) + { + cur = (struct esp32s3_dmadesc_s *) + GET_GDMA_CH_REG(DMA_OUT_EOF_DES_ADDR_CH0_REG, + priv->dma_channel); + + /* Schedule completion of the transfer on the worker thread */ + + i2s_tx_schedule(priv, cur); + } + } + + return 0; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rx_interrupt + * + * Description: + * Common I2S DMA interrupt handler + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info + * arg - I2S controller private data + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rx_interrupt(int irq, void *context, void *arg) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)arg; + struct esp32s3_dmadesc_s *cur = NULL; + + uint32_t status = GET_GDMA_CH_REG(DMA_IN_INT_ST_CH0_REG, + priv->dma_channel); + + SET_GDMA_CH_REG(DMA_IN_INT_CLR_CH0_REG, priv->dma_channel, + UINT32_MAX); + + if (priv->config->rx_en) + { + if (status & DMA_IN_SUC_EOF_CH0_INT_ST) + { + cur = (struct esp32s3_dmadesc_s *) + GET_GDMA_CH_REG(DMA_IN_SUC_EOF_DES_ADDR_CH0_REG, + priv->dma_channel); + + /* Schedule completion of the transfer on the worker thread */ + + i2s_rx_schedule(priv, cur); + } + } + + return 0; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_getmclkfrequency + * + * Description: + * Get the current master clock frequency. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Returns the current master clock. + * + ****************************************************************************/ + +static uint32_t i2s_getmclkfrequency(struct i2s_dev_s *dev) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + return priv->mclk_freq; +} + +/**************************************************************************** + * Name: i2s_setmclkfrequency + * + * Description: + * Set the master clock frequency. Usually, the MCLK is a multiple of the + * sample rate. Most of the audio codecs require setting specific MCLK + * frequency according to the sample rate. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The I2S master clock's frequency + * + * Returned Value: + * Returns the resulting master clock or a negated errno value on failure. + * + ****************************************************************************/ + +static uint32_t i2s_setmclkfrequency(struct i2s_dev_s *dev, + uint32_t frequency) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + /* Check if the master clock frequency is beyond the highest possible + * value and return an error. + */ + + if (frequency >= (I2S_LL_BASE_CLK / 2)) + { + return -EINVAL; + } + + priv->mclk_freq = frequency; + + return frequency; +} + +/**************************************************************************** + * Name: i2s_txchannels + * + * Description: + * Set the I2S TX number of channels. + * + * Input Parameters: + * dev - Device-specific state data + * channels - The I2S numbers of channels + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int i2s_txchannels(struct i2s_dev_s *dev, uint8_t channels) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + uint32_t channels_mask; + + if (priv->config->tx_en) + { + if (channels != 1 && channels != 2) + { + return -EINVAL; + } + + i2s_tx_channel_stop(priv); + + priv->channels = channels; + + /* Always consider two channels. For mono (1-channel), we set the + * I2S_TX_TDM_CHAN1_EN to 0 and I2S_TX_CHAN_EQUAL to 1 to send out + * the data of the previous channel. + */ + + /* I2S_TX_TDM_TOT_CHAN_NUM = channels - 1 */ + + modifyreg32(I2S_TX_TDM_CTRL_REG(priv->config->port), + I2S_TX_TDM_TOT_CHAN_NUM_M, + FIELD_TO_VALUE(I2S_TX_TDM_TOT_CHAN_NUM, 1)); + + channels_mask = getreg32(I2S_TX_TDM_CTRL_REG(priv->config->port)); + channels_mask &= 0xffff0000; + + if (priv->channels == 1) + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + I2S_TX_MONO_M, I2S_TX_MONO); + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + I2S_TX_CHAN_EQUAL_M, I2S_TX_CHAN_EQUAL); + channels_mask |= I2S_TX_TDM_CHAN0_EN; + } + else + { + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + I2S_TX_MONO_M, 0); + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + I2S_TX_CHAN_EQUAL_M, 0); + channels_mask |= I2S_TX_TDM_CHAN0_EN | I2S_TX_TDM_CHAN1_EN; + } + + putreg32(channels_mask, I2S_TX_TDM_CTRL_REG(priv->config->port)); + + /* Set I2S_TX_UPDATE bit to update the configs. + * This bit is automatically cleared. + */ + + modifyreg32(I2S_TX_CONF_REG(priv->config->port), + 0, I2S_TX_UPDATE); + + i2s_tx_channel_start(priv); + + return OK; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxchannels + * + * Description: + * Set the I2S RX number of channels. + * + * Input Parameters: + * dev - Device-specific state data + * channels - The I2S numbers of channels + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_rxchannels(struct i2s_dev_s *dev, uint8_t channels) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + if (priv->config->rx_en) + { + if (channels != 1 && channels != 2) + { + return -EINVAL; + } + + priv->channels = channels; + return OK; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_txsamplerate + * + * Description: + * Set the I2S TX sample rate. NOTE: This will have no effect if (1) the + * driver does not support an I2S transmitter or if (2) the sample rate is + * driven by the I2S frame clock. This may also have unexpected side- + * effects of the TX sample is coupled with the RX sample rate. + * + * Input Parameters: + * dev - Device-specific state data + * rate - The I2S sample rate in samples (not bits) per second + * + * Returned Value: + * Returns the resulting bitrate + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static uint32_t i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + if (priv->config->tx_en) + { + i2s_tx_channel_stop(priv); + + priv->rate = rate; + + rate = i2s_set_clock(priv); + + i2s_tx_channel_start(priv); + + return rate; + } + + return 0; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxsamplerate + * + * Description: + * Set the I2S RX sample rate. + * + * Input Parameters: + * dev - Device-specific state data + * rate - The I2S sample rate in samples (not bits) per second + * + * Returned Value: + * Returns the resulting bitrate + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static uint32_t i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + if (priv->config->rx_en) + { + i2s_rx_channel_stop(priv); + + priv->rate = rate; + + rate = i2s_set_clock(priv); + + i2s_rx_channel_start(priv); + + return rate; + } + + return 0; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_txdatawidth + * + * Description: + * Set the I2S TX data width. The TX bitrate is determined by + * sample_rate * data_width. + * + * Input Parameters: + * dev - Device-specific state data + * width - The I2S data with in bits. + * + * Returned Value: + * Returns the resulting data width + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static uint32_t i2s_txdatawidth(struct i2s_dev_s *dev, int bits) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + if (priv->config->tx_en) + { + i2s_tx_channel_stop(priv); + + priv->data_width = bits; + + i2s_set_datawidth(priv); + + i2s_tx_channel_start(priv); + + return bits; + } + + return 0; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_rxdatawidth + * + * Description: + * Set the I2S RX data width. The RX bitrate is determined by + * sample_rate * data_width. + * + * Input Parameters: + * dev - Device-specific state data + * width - The I2S data with in bits. + * + * Returned Value: + * Returns the resulting data width + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static uint32_t i2s_rxdatawidth(struct i2s_dev_s *dev, int bits) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + if (priv->config->rx_en) + { + i2s_rx_channel_stop(priv); + + priv->data_width = bits; + + i2s_set_datawidth(priv); + + i2s_rx_channel_start(priv); + + return bits; + } + + return 0; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_send + * + * Description: + * Send a block of data on I2S. + * + * Input Parameters: + * dev - Device-specific state data + * apb - A pointer to the audio buffer from which to send data + * callback - A user provided callback function that will be called at + * the completion of the transfer. + * arg - An opaque argument that will be provided to the callback + * when the transfer complete + * timeout - The timeout value to use. The transfer will be cancelled + * and an ETIMEDOUT error will be reported if this timeout + * elapsed without completion of the DMA transfer. Units + * are system clock ticks. Zero means no timeout. + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_TX +static int i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, uint32_t timeout) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + if (priv->config->tx_en) + { + struct esp32s3_buffer_s *bfcontainer; + int ret = OK; + uint32_t nbytes; + uint32_t nsamp; + + /* Check audio buffer data size from the upper half. If the buffer + * size is not a multiple of the data width, the remaining bytes + * must be sent along with the next audio buffer. + */ + + nbytes = (apb->nbytes - apb->curbyte) + priv->tx.carry.bytes; + + nbytes -= (nbytes % (priv->data_width / 8)); + + if (nbytes > (ESP32S3_DMA_DATALEN_MAX * I2S_DMADESC_NUM)) + { + i2serr("Required buffer size can't fit into DMA outlink " + "(exceeds in %" PRIu32 " bytes). Try to increase the " + "number of the DMA descriptors (CONFIG_I2S_DMADESC_NUM).", + nbytes - (ESP32S3_DMA_DATALEN_MAX * I2S_DMADESC_NUM)); + return -EFBIG; + } + + /* Allocate a buffer container in advance */ + + bfcontainer = i2s_buf_allocate(priv); + if (bfcontainer == NULL) + { + i2serr("Failed to allocate the buffer container"); + return -ENOMEM; + } + + /* Get exclusive access to the I2S driver data */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + goto errout_with_buf; + } + + /* Add a reference to the audio buffer */ + + apb_reference(apb); + + /* Initialize the buffer container structure */ + + bfcontainer->callback = callback; + bfcontainer->timeout = timeout; + bfcontainer->arg = arg; + bfcontainer->apb = apb; + bfcontainer->nbytes = nbytes; + bfcontainer->result = -EBUSY; + + ret = i2s_txdma_setup(priv, bfcontainer); + + if (ret != OK) + { + goto errout_with_buf; + } + + i2sinfo("Queued %d bytes into DMA buffers\n", apb->nbytes); + i2s_dump_buffer("Audio pipeline buffer:", &apb->samp[apb->curbyte], + apb->nbytes - apb->curbyte); + + nxmutex_unlock(&priv->lock); + + return OK; + +errout_with_buf: + nxmutex_unlock(&priv->lock); + i2s_buf_free(priv, bfcontainer); + return ret; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_TX */ + +/**************************************************************************** + * Name: i2s_receive + * + * Description: + * Receive a block of data on I2S. + * + * Input Parameters: + * dev - Device-specific state data + * apb - A pointer to the audio buffer in which to receive data + * callback - A user provided callback function that will be called at + * the completion of the transfer. + * arg - An opaque argument that will be provided to the callback + * when the transfer complete + * timeout - The timeout value to use. The transfer will be cancelled + * and an ETIMEDOUT error will be reported if this timeout + * elapsed without completion of the DMA transfer. Units + * are system clock ticks. Zero means no timeout. + * + * Returned Value: + * OK on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef I2S_HAVE_RX +static int i2s_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, uint32_t timeout) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + + if (priv->config->rx_en) + { + struct esp32s3_buffer_s *bfcontainer; + int ret = OK; + uint32_t nbytes; + uint32_t nsamp; + + /* Check max audio buffer data size from the upper half and align the + * receiving buffer according to the data width. + */ + + nbytes = apb->nmaxbytes; + + nbytes -= (nbytes % (priv->data_width / 8)); + + nbytes = MIN(nbytes, ESP32S3_DMA_DATALEN_MAX); + + /* Allocate a buffer container in advance */ + + bfcontainer = i2s_buf_allocate(priv); + if (bfcontainer == NULL) + { + i2serr("Failed to allocate the buffer container"); + return -ENOMEM; + } + + /* Get exclusive access to the I2S driver data */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + goto errout_with_buf; + } + + /* Add a reference to the audio buffer */ + + apb_reference(apb); + + /* Initialize the buffer container structure */ + + bfcontainer->callback = callback; + bfcontainer->timeout = timeout; + bfcontainer->arg = arg; + bfcontainer->apb = apb; + bfcontainer->nbytes = nbytes; + bfcontainer->result = -EBUSY; + + ret = i2s_rxdma_setup(priv, bfcontainer); + + if (ret != OK) + { + goto errout_with_buf; + } + + i2sinfo("Prepared %d bytes to receive DMA buffers\n", apb->nmaxbytes); + i2s_dump_buffer("Audio pipeline buffer:", &apb->samp[apb->curbyte], + apb->nbytes - apb->curbyte); + + nxmutex_unlock(&priv->lock); + + return OK; + +errout_with_buf: + nxmutex_unlock(&priv->lock); + i2s_buf_free(priv, bfcontainer); + return ret; + } + + return -ENOTTY; +} +#endif /* I2S_HAVE_RX */ + +/**************************************************************************** + * Name: i2s_ioctl + * + * Description: + * Implement the lower-half logic ioctl commands + * + * Input parameters: + * dev - A reference to the lower-half I2S driver device + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg) +{ + struct esp32s3_i2s_s *priv = (struct esp32s3_i2s_s *)dev; + struct audio_buf_desc_s *bufdesc; + int ret = -ENOTTY; + + switch (cmd) + { + /* AUDIOIOC_START - Start the audio stream. + * + * ioctl argument: Audio session + */ + + case AUDIOIOC_START: + { + i2sinfo("AUDIOIOC_START\n"); + + ret = OK; + } + break; + + /* AUDIOIOC_ALLOCBUFFER - Allocate an audio buffer + * + * ioctl argument: pointer to an audio_buf_desc_s structure + */ + + case AUDIOIOC_ALLOCBUFFER: + { + i2sinfo("AUDIOIOC_ALLOCBUFFER\n"); + + bufdesc = (struct audio_buf_desc_s *) arg; + ret = apb_alloc(bufdesc); + } + break; + + /* AUDIOIOC_FREEBUFFER - Free an audio buffer + * + * ioctl argument: pointer to an audio_buf_desc_s structure + */ + + case AUDIOIOC_FREEBUFFER: + { + i2sinfo("AUDIOIOC_FREEBUFFER\n"); + + bufdesc = (struct audio_buf_desc_s *) arg; + DEBUGASSERT(bufdesc->u.buffer != NULL); + apb_free(bufdesc->u.buffer); + ret = sizeof(struct audio_buf_desc_s); + } + break; + + default: + break; + } + + return ret; +} + +/**************************************************************************** + * Name: i2s_dma_setup + * + * Description: + * Configure the DMA for the I2S peripheral + * + * Input Parameters: + * priv - Partially initialized I2S device structure. This function + * will complete the I2S specific portions of the initialization + * regarding the DMA operation. + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int i2s_dma_setup(struct esp32s3_i2s_s *priv) +{ + int ret; + int i2s_dma_dev; + + /* Initialize GDMA controller */ + + esp32s3_dma_init(); + + if (priv->config->port == 0) + { + i2s_dma_dev = ESP32S3_DMA_PERIPH_I2S0; + } + else + { + i2s_dma_dev = ESP32S3_DMA_PERIPH_I2S1; + } + + /* Request a GDMA channel for the I2S peripheral */ + + priv->dma_channel = esp32s3_dma_request(i2s_dma_dev, 1, 1, false); + if (priv->dma_channel < 0) + { + i2serr("Failed to allocate GDMA channel\n"); + + return ERROR; + } + + /* Set up to receive GDMA interrupts on the current CPU. Each TX/RX channel + * will be assigned to a different CPU interrupt. + */ + + priv->cpu = up_cpu_index(); + +#ifdef I2S_HAVE_TX + if (priv->config->tx_en) + { + int periph = ESP32S3_PERIPH_DMA_OUT_CH0 + priv->dma_channel; + int cpuint = esp32s3_setup_irq(priv->cpu, periph, 1, + ESP32S3_CPUINT_LEVEL); + if (cpuint < 0) + { + i2serr("Failed to allocate a CPU interrupt.\n"); + return ERROR; + } + + priv->tx_irq = ESP32S3_PERIPH2IRQ(periph); + ret = irq_attach(priv->tx_irq, i2s_tx_interrupt, priv); + if (ret != OK) + { + i2serr("Couldn't attach IRQ to handler.\n"); + esp32s3_teardown_irq(priv->cpu, periph, cpuint); + return ret; + } + } +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + if (priv->config->rx_en) + { + int periph = ESP32S3_PERIPH_DMA_IN_CH0 + priv->dma_channel; + int cpuint = esp32s3_setup_irq(priv->cpu, periph, 1, + ESP32S3_CPUINT_LEVEL); + if (cpuint < 0) + { + i2serr("Failed to allocate a CPU interrupt.\n"); + return ERROR; + } + + priv->rx_irq = ESP32S3_PERIPH2IRQ(periph); + ret = irq_attach(priv->rx_irq, i2s_rx_interrupt, priv); + if (ret != OK) + { + i2serr("Couldn't attach IRQ to handler.\n"); + esp32s3_teardown_irq(priv->cpu, periph, cpuint); + return ret; + } + } +#endif /* I2S_HAVE_RX */ + + return OK; +} + +/**************************************************************************** + * Name: esp32s3_i2sbus_initialize + * + * Description: + * Initialize the selected I2S port + * + * Input Parameters: + * Port number (for hardware that has multiple I2S interfaces) + * + * Returned Value: + * Valid I2S device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct i2s_dev_s *esp32s3_i2sbus_initialize(int port) +{ + int ret; + struct esp32s3_i2s_s *priv = NULL; + irqstate_t flags; + + i2sinfo("port: %d\n", port); + + /* Statically allocated I2S' device strucuture */ + + switch (port) + { +#ifdef CONFIG_ESP32S3_I2S0 + case ESP32S3_I2S0: + priv = &esp32s3_i2s0_priv; + break; +#endif +#ifdef CONFIG_ESP32S3_I2S1 + case ESP32S3_I2S1: + priv = &esp32s3_i2s1_priv; + break; +#endif + default: + return NULL; + } + + flags = spin_lock_irqsave(&priv->slock); + + i2s_configure(priv); + + /* Allocate buffer containers */ + + ret = i2s_buf_initialize(priv); + if (ret < 0) + { + goto err; + } + + ret = i2s_dma_setup(priv); + if (ret < 0) + { + goto err; + } + +#ifdef I2S_HAVE_TX + /* Start TX channel */ + + if (priv->config->tx_en) + { + priv->tx_started = false; + i2s_tx_channel_start(priv); + } +#endif /* I2S_HAVE_TX */ + +#ifdef I2S_HAVE_RX + /* Start RX channel */ + + if (priv->config->rx_en) + { + priv->rx_started = false; + i2s_rx_channel_start(priv); + } +#endif /* I2S_HAVE_RX */ + + spin_unlock_irqrestore(&priv->slock, flags); + + /* Success exit */ + + i2sinfo("I2S%d was successfully initialized\n", priv->config->port); + + return &priv->dev; + + /* Failure exit */ + +err: + spin_unlock_irqrestore(&priv->slock, flags); + return NULL; +} + +#endif /* CONFIG_ESP32S3_I2S */ diff --git a/arch/xtensa/src/esp32s3/esp32s3_i2s.h b/arch/xtensa/src/esp32s3/esp32s3_i2s.h new file mode 100644 index 00000000000..c485beda05f --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_i2s.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_i2s.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_I2S_H +#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_I2S_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifdef CONFIG_ESP32S3_I2S + +#define ESP32S3_I2S0 0 +#define ESP32S3_I2S1 1 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_i2sbus_initialize + * + * Description: + * Initialize the selected I2S port + * + * Input Parameters: + * Port number (for hardware that has multiple I2S interfaces) + * + * Returned Value: + * Valid I2S device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct i2s_dev_s *esp32s3_i2sbus_initialize(int port); + +#endif /* CONFIG_ESP32S3_I2S */ + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_I2S_H */ diff --git a/arch/xtensa/src/esp32s3/hardware/esp32s3_i2s.h b/arch/xtensa/src/esp32s3/hardware/esp32s3_i2s.h new file mode 100644 index 00000000000..014fd358bd6 --- /dev/null +++ b/arch/xtensa/src/esp32s3/hardware/esp32s3_i2s.h @@ -0,0 +1,1888 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/hardware/esp32s3_i2s.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32S3_HARDWARE_ESP32S3_I2S_H +#define __ARCH_XTENSA_SRC_ESP32S3_HARDWARE_ESP32S3_I2S_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "esp32s3_soc.h" + +#define I2S_INT_RAW_REG(i) (REG_I2S_BASE(i) + 0xC) + +/* I2S_TX_HUNG_INT_RAW : RO/WTC/SS ;bitpos:[3] ;default: 1'b0 ; */ + +/* Description: The raw interrupt status bit for the i2s_tx_hung_int + * interrupt. + */ + +#define I2S_TX_HUNG_INT_RAW (BIT(3)) +#define I2S_TX_HUNG_INT_RAW_M (BIT(3)) +#define I2S_TX_HUNG_INT_RAW_V 0x1 +#define I2S_TX_HUNG_INT_RAW_S 3 + +/* I2S_RX_HUNG_INT_RAW : RO/WTC/SS ;bitpos:[2] ;default: 1'b0 ; */ + +/* Description: The raw interrupt status bit for the i2s_rx_hung_int + * interrupt. + */ + +#define I2S_RX_HUNG_INT_RAW (BIT(2)) +#define I2S_RX_HUNG_INT_RAW_M (BIT(2)) +#define I2S_RX_HUNG_INT_RAW_V 0x1 +#define I2S_RX_HUNG_INT_RAW_S 2 + +/* I2S_TX_DONE_INT_RAW : RO/WTC/SS ;bitpos:[1] ;default: 1'b0 ; */ + +/* Description: The raw interrupt status bit for the i2s_tx_done_int + * interrupt. + */ + +#define I2S_TX_DONE_INT_RAW (BIT(1)) +#define I2S_TX_DONE_INT_RAW_M (BIT(1)) +#define I2S_TX_DONE_INT_RAW_V 0x1 +#define I2S_TX_DONE_INT_RAW_S 1 + +/* I2S_RX_DONE_INT_RAW : RO/WTC/SS ;bitpos:[0] ;default: 1'b0 ; */ + +/* Description: The raw interrupt status bit for the i2s_rx_done_int + * interrupt. + */ + +#define I2S_RX_DONE_INT_RAW (BIT(0)) +#define I2S_RX_DONE_INT_RAW_M (BIT(0)) +#define I2S_RX_DONE_INT_RAW_V 0x1 +#define I2S_RX_DONE_INT_RAW_S 0 + +#define I2S_INT_ST_REG(i) (REG_I2S_BASE(i) + 0x10) + +/* I2S_TX_HUNG_INT_ST : RO ;bitpos:[3] ;default: 1'b0 ; */ + +/* Description: The masked interrupt status bit for the i2s_tx_hung_int + * interrupt. + */ + +#define I2S_TX_HUNG_INT_ST (BIT(3)) +#define I2S_TX_HUNG_INT_ST_M (BIT(3)) +#define I2S_TX_HUNG_INT_ST_V 0x1 +#define I2S_TX_HUNG_INT_ST_S 3 + +/* I2S_RX_HUNG_INT_ST : RO ;bitpos:[2] ;default: 1'b0 ; */ + +/* Description: The masked interrupt status bit for the i2s_rx_hung_int + * interrupt. + */ + +#define I2S_RX_HUNG_INT_ST (BIT(2)) +#define I2S_RX_HUNG_INT_ST_M (BIT(2)) +#define I2S_RX_HUNG_INT_ST_V 0x1 +#define I2S_RX_HUNG_INT_ST_S 2 + +/* I2S_TX_DONE_INT_ST : RO ;bitpos:[1] ;default: 1'b0 ; */ + +/* Description: The masked interrupt status bit for the i2s_tx_done_int + * interrupt. + */ + +#define I2S_TX_DONE_INT_ST (BIT(1)) +#define I2S_TX_DONE_INT_ST_M (BIT(1)) +#define I2S_TX_DONE_INT_ST_V 0x1 +#define I2S_TX_DONE_INT_ST_S 1 + +/* I2S_RX_DONE_INT_ST : RO ;bitpos:[0] ;default: 1'b0 ; */ + +/* Description: The masked interrupt status bit for the i2s_rx_done_int + * interrupt. + */ + +#define I2S_RX_DONE_INT_ST (BIT(0)) +#define I2S_RX_DONE_INT_ST_M (BIT(0)) +#define I2S_RX_DONE_INT_ST_V 0x1 +#define I2S_RX_DONE_INT_ST_S 0 + +#define I2S_INT_ENA_REG(i) (REG_I2S_BASE(i) + 0x14) + +/* I2S_TX_HUNG_INT_ENA : R/W ;bitpos:[3] ;default: 1'b0 ; */ + +/* Description: The interrupt enable bit for the i2s_tx_hung_int + * interrupt. + */ + +#define I2S_TX_HUNG_INT_ENA (BIT(3)) +#define I2S_TX_HUNG_INT_ENA_M (BIT(3)) +#define I2S_TX_HUNG_INT_ENA_V 0x1 +#define I2S_TX_HUNG_INT_ENA_S 3 + +/* I2S_RX_HUNG_INT_ENA : R/W ;bitpos:[2] ;default: 1'b0 ; */ + +/* Description: The interrupt enable bit for the i2s_rx_hung_int + * interrupt. + */ + +#define I2S_RX_HUNG_INT_ENA (BIT(2)) +#define I2S_RX_HUNG_INT_ENA_M (BIT(2)) +#define I2S_RX_HUNG_INT_ENA_V 0x1 +#define I2S_RX_HUNG_INT_ENA_S 2 + +/* I2S_TX_DONE_INT_ENA : R/W ;bitpos:[1] ;default: 1'b0 ; */ + +/* Description: The interrupt enable bit for the i2s_tx_done_int + * interrupt. + */ + +#define I2S_TX_DONE_INT_ENA (BIT(1)) +#define I2S_TX_DONE_INT_ENA_M (BIT(1)) +#define I2S_TX_DONE_INT_ENA_V 0x1 +#define I2S_TX_DONE_INT_ENA_S 1 + +/* I2S_RX_DONE_INT_ENA : R/W ;bitpos:[0] ;default: 1'b0 ; */ + +/* Description: The interrupt enable bit for the i2s_rx_done_int + * interrupt. + */ + +#define I2S_RX_DONE_INT_ENA (BIT(0)) +#define I2S_RX_DONE_INT_ENA_M (BIT(0)) +#define I2S_RX_DONE_INT_ENA_V 0x1 +#define I2S_RX_DONE_INT_ENA_S 0 + +#define I2S_INT_CLR_REG(i) (REG_I2S_BASE(i) + 0x18) + +/* I2S_TX_HUNG_INT_CLR : WT ;bitpos:[3] ;default: 1'b0 ; */ + +/* Description: Set this bit to clear the i2s_tx_hung_int interrupt. */ + +#define I2S_TX_HUNG_INT_CLR (BIT(3)) +#define I2S_TX_HUNG_INT_CLR_M (BIT(3)) +#define I2S_TX_HUNG_INT_CLR_V 0x1 +#define I2S_TX_HUNG_INT_CLR_S 3 + +/* I2S_RX_HUNG_INT_CLR : WT ;bitpos:[2] ;default: 1'b0 ; */ + +/* Description: Set this bit to clear the i2s_rx_hung_int interrupt. */ + +#define I2S_RX_HUNG_INT_CLR (BIT(2)) +#define I2S_RX_HUNG_INT_CLR_M (BIT(2)) +#define I2S_RX_HUNG_INT_CLR_V 0x1 +#define I2S_RX_HUNG_INT_CLR_S 2 + +/* I2S_TX_DONE_INT_CLR : WT ;bitpos:[1] ;default: 1'b0 ; */ + +/* Description: Set this bit to clear the i2s_tx_done_int interrupt. */ + +#define I2S_TX_DONE_INT_CLR (BIT(1)) +#define I2S_TX_DONE_INT_CLR_M (BIT(1)) +#define I2S_TX_DONE_INT_CLR_V 0x1 +#define I2S_TX_DONE_INT_CLR_S 1 + +/* I2S_RX_DONE_INT_CLR : WT ;bitpos:[0] ;default: 1'b0 ; */ + +/* Description: Set this bit to clear the i2s_rx_done_int interrupt. */ + +#define I2S_RX_DONE_INT_CLR (BIT(0)) +#define I2S_RX_DONE_INT_CLR_M (BIT(0)) +#define I2S_RX_DONE_INT_CLR_V 0x1 +#define I2S_RX_DONE_INT_CLR_S 0 + +#define I2S_RX_CONF_REG(i) (REG_I2S_BASE(i) + 0x20) + +/* I2S_RX_PDM_SINC_DSR_16_EN : R/W ;bitpos:[22] ;default: 1'h0 ; */ + +/* Description: Configure the down sampling rate of PDM RX filter group1 + * module. + * 1: The down sa mpling rate is 128. + * 0: down sampling rate is 64. + */ + +#define I2S_RX_PDM_SINC_DSR_16_EN (BIT(22)) +#define I2S_RX_PDM_SINC_DSR_16_EN_M (BIT(22)) +#define I2S_RX_PDM_SINC_DSR_16_EN_V 0x1 +#define I2S_RX_PDM_SINC_DSR_16_EN_S 22 + +/* I2S_RX_PDM2PCM_EN : R/W ;bitpos:[21] ;default: 1'h0 ; */ + +/* Description: + * 1: Enable PDM2PCM RX mode. + * 0: DIsable. + */ + +#define I2S_RX_PDM2PCM_EN (BIT(21)) +#define I2S_RX_PDM2PCM_EN_M (BIT(21)) +#define I2S_RX_PDM2PCM_EN_V 0x1 +#define I2S_RX_PDM2PCM_EN_S 21 + +/* I2S_RX_PDM_EN : R/W ;bitpos:[20] ;default: 1'h0 ; */ + +/* Description: + * 1: Enable I2S PDM Rx mode. + * 0: Disable. + */ + +#define I2S_RX_PDM_EN (BIT(20)) +#define I2S_RX_PDM_EN_M (BIT(20)) +#define I2S_RX_PDM_EN_V 0x1 +#define I2S_RX_PDM_EN_S 20 + +/* I2S_RX_TDM_EN : R/W ;bitpos:[19] ;default: 1'h0 ; */ + +/* Description: + * 1: Enable I2S TDM Rx mode. + * 0: Disable. + */ + +#define I2S_RX_TDM_EN (BIT(19)) +#define I2S_RX_TDM_EN_M (BIT(19)) +#define I2S_RX_TDM_EN_V 0x1 +#define I2S_RX_TDM_EN_S 19 + +/* I2S_RX_BIT_ORDER : R/W ;bitpos:[18] ;default: 1'h0 ; */ + +/* Description: I2S Rx bit endian. 1:small endian, the LSB is received + * first. 0:big endian, the MSB is received first.. + */ + +#define I2S_RX_BIT_ORDER (BIT(18)) +#define I2S_RX_BIT_ORDER_M (BIT(18)) +#define I2S_RX_BIT_ORDER_V 0x1 +#define I2S_RX_BIT_ORDER_S 18 + +/* I2S_RX_WS_IDLE_POL : R/W ;bitpos:[17] ;default: 1'h0 ; */ + +/* Description: + * 0: WS should be 0 when receiving left channel data, + * and WS is 1in right channel. + * 1: WS should be 1 when receiving left channel data, and WS is 0 + * in right channel. + */ + +#define I2S_RX_WS_IDLE_POL (BIT(17)) +#define I2S_RX_WS_IDLE_POL_M (BIT(17)) +#define I2S_RX_WS_IDLE_POL_V 0x1 +#define I2S_RX_WS_IDLE_POL_S 17 + +/* I2S_RX_24_FILL_EN : R/W ;bitpos:[16] ;default: 1'h0 ; */ + +/* Description: + * 1: store 24 channel bits to 32 bits. + * 0: store 24 channel bits to 24 bits. + */ + +#define I2S_RX_24_FILL_EN (BIT(16)) +#define I2S_RX_24_FILL_EN_M (BIT(16)) +#define I2S_RX_24_FILL_EN_V 0x1 +#define I2S_RX_24_FILL_EN_S 16 + +/* I2S_RX_LEFT_ALIGN : R/W ;bitpos:[15] ;default: 1'b1 ; */ + +/* Description: + * 1: I2S RX left alignment mode. + * 0: I2S RX right alignment mode.. + */ + +#define I2S_RX_LEFT_ALIGN (BIT(15)) +#define I2S_RX_LEFT_ALIGN_M (BIT(15)) +#define I2S_RX_LEFT_ALIGN_V 0x1 +#define I2S_RX_LEFT_ALIGN_S 15 + +/* I2S_RX_STOP_MODE : R/W ;bitpos:[14:13] ;default: 2'd0 ; */ + +/* Description: + * 0: I2S Rx only stop when reg_rx_start is cleared. + * 1: Stop when reg_rx_start is 0 or in_suc_eof is 1. + * 2: Stop I2S RX when reg_rx_start is 0 or RX FIFO is full. + */ + +#define I2S_RX_STOP_MODE 0x00000003 +#define I2S_RX_STOP_MODE_M ((I2S_RX_STOP_MODE_V)<<(I2S_RX_STOP_MODE_S)) +#define I2S_RX_STOP_MODE_V 0x3 +#define I2S_RX_STOP_MODE_S 13 + +/* I2S_RX_PCM_BYPASS : R/W ;bitpos:[12] ;default: 1'h1 ; */ + +/* Description: Set this bit to bypass Compress/Decompress module + * for received data.. + */ + +#define I2S_RX_PCM_BYPASS (BIT(12)) +#define I2S_RX_PCM_BYPASS_M (BIT(12)) +#define I2S_RX_PCM_BYPASS_V 0x1 +#define I2S_RX_PCM_BYPASS_S 12 + +/* I2S_RX_PCM_CONF : R/W ;bitpos:[11:10] ;default: 2'h1 ; */ + +/* Description: I2S RX compress/decompress configuration bit. + * 0 (atol): A-Law decompress, + * 1 (ltoa) : A-Law compress, + * 2 (utol) : u-Law decompress, + * 3 (ltou) : u-Law compress. + */ + +#define I2S_RX_PCM_CONF 0x00000003 +#define I2S_RX_PCM_CONF_M ((I2S_RX_PCM_CONF_V)<<(I2S_RX_PCM_CONF_S)) +#define I2S_RX_PCM_CONF_V 0x3 +#define I2S_RX_PCM_CONF_S 10 + +/* I2S_RX_MONO_FST_VLD : R/W ;bitpos:[9] ;default: 1'b1 ; */ + +/* Description: + * 1: The first channel data value is valid in I2S RX mono mode. + * 0: The second channel data value is valid in I2S RX mono mode. + */ + +#define I2S_RX_MONO_FST_VLD (BIT(9)) +#define I2S_RX_MONO_FST_VLD_M (BIT(9)) +#define I2S_RX_MONO_FST_VLD_V 0x1 +#define I2S_RX_MONO_FST_VLD_S 9 + +/* I2S_RX_UPDATE : R/W/SC ;bitpos:[8] ;default: 1'b0 ; */ + +/* Description: + * Set 1 to update I2S RX registers from APB clock domain to I2S RX clock + * domain. This bit will be cleared by hardware after update register + * done. + */ + +#define I2S_RX_UPDATE (BIT(8)) +#define I2S_RX_UPDATE_M (BIT(8)) +#define I2S_RX_UPDATE_V 0x1 +#define I2S_RX_UPDATE_S 8 + +/* I2S_RX_BIG_ENDIAN : R/W ;bitpos:[7] ;default: 1'b0 ; */ + +/* Description: + * I2S Rx byte endian + * 1: low addr value to high addr. + * 0: low addr with low addr value. + */ + +#define I2S_RX_BIG_ENDIAN (BIT(7)) +#define I2S_RX_BIG_ENDIAN_M (BIT(7)) +#define I2S_RX_BIG_ENDIAN_V 0x1 +#define I2S_RX_BIG_ENDIAN_S 7 + +/* I2S_RX_MONO : R/W ;bitpos:[5] ;default: 1'b0 ; */ + +/* Description: Set this bit to enable receiver in mono mode. */ + +#define I2S_RX_MONO (BIT(5)) +#define I2S_RX_MONO_M (BIT(5)) +#define I2S_RX_MONO_V 0x1 +#define I2S_RX_MONO_S 5 + +/* I2S_RX_SLAVE_MOD : R/W ;bitpos:[3] ;default: 1'b0 ; */ + +/* Description: Set this bit to enable slave receiver mode. */ + +#define I2S_RX_SLAVE_MOD (BIT(3)) +#define I2S_RX_SLAVE_MOD_M (BIT(3)) +#define I2S_RX_SLAVE_MOD_V 0x1 +#define I2S_RX_SLAVE_MOD_S 3 + +/* I2S_RX_START : R/W ;bitpos:[2] ;default: 1'b0 ; */ + +/* Description: Set this bit to start receiving data. */ + +#define I2S_RX_START (BIT(2)) +#define I2S_RX_START_M (BIT(2)) +#define I2S_RX_START_V 0x1 +#define I2S_RX_START_S 2 + +/* I2S_RX_FIFO_RESET : WT ;bitpos:[1] ;default: 1'b0 ; */ + +/* Description: Set this bit to reset Rx AFIFO. */ + +#define I2S_RX_FIFO_RESET (BIT(1)) +#define I2S_RX_FIFO_RESET_M (BIT(1)) +#define I2S_RX_FIFO_RESET_V 0x1 +#define I2S_RX_FIFO_RESET_S 1 + +/* I2S_RX_RESET : WT ;bitpos:[0] ;default: 1'b0 ; */ + +/* Description: Set this bit to reset receiver. */ + +#define I2S_RX_RESET (BIT(0)) +#define I2S_RX_RESET_M (BIT(0)) +#define I2S_RX_RESET_V 0x1 +#define I2S_RX_RESET_S 0 + +#define I2S_TX_CONF_REG(i) (REG_I2S_BASE(i) + 0x24) + +/* I2S_SIG_LOOPBACK : R/W ;bitpos:[27] ;default: 1'b0 ; */ + +/* Description: + * Enable signal loop back mode with transmitter module and receiver + * module sharing the same WS and BCK signals. + */ + +#define I2S_SIG_LOOPBACK (BIT(27)) +#define I2S_SIG_LOOPBACK_M (BIT(27)) +#define I2S_SIG_LOOPBACK_V 0x1 +#define I2S_SIG_LOOPBACK_S 27 + +/* I2S_TX_CHAN_MOD : R/W ;bitpos:[26:24] ;default: 3'b0 ; */ + +/* Description: I2S transmitter channel mode configuration bits. */ + +#define I2S_TX_CHAN_MOD 0x00000007 +#define I2S_TX_CHAN_MOD_M ((I2S_TX_CHAN_MOD_V)<<(I2S_TX_CHAN_MOD_S)) +#define I2S_TX_CHAN_MOD_V 0x7 +#define I2S_TX_CHAN_MOD_S 24 + +/* I2S_TX_PDM_EN : R/W ;bitpos:[20] ;default: 1'h0 ; */ + +/* Description: + * 1: Enable I2S PDM Tx mode + * 0: Disable. + */ + +#define I2S_TX_PDM_EN (BIT(20)) +#define I2S_TX_PDM_EN_M (BIT(20)) +#define I2S_TX_PDM_EN_V 0x1 +#define I2S_TX_PDM_EN_S 20 + +/* I2S_TX_TDM_EN : R/W ;bitpos:[19] ;default: 1'h0 ; */ + +/* Description: + * 1: Enable I2S TDM Tx mode + * 0: Disable. + */ + +#define I2S_TX_TDM_EN (BIT(19)) +#define I2S_TX_TDM_EN_M (BIT(19)) +#define I2S_TX_TDM_EN_V 0x1 +#define I2S_TX_TDM_EN_S 19 + +/* I2S_TX_BIT_ORDER : R/W ;bitpos:[18] ;default: 1'h0 ; */ + +/* Description: I2S Tx bit endian. + * 1:small endian, the LSB is sent first. + * 0:big endian, the MSB is sent first. + */ + +#define I2S_TX_BIT_ORDER (BIT(18)) +#define I2S_TX_BIT_ORDER_M (BIT(18)) +#define I2S_TX_BIT_ORDER_V 0x1 +#define I2S_TX_BIT_ORDER_S 18 + +/* I2S_TX_WS_IDLE_POL : R/W ;bitpos:[17] ;default: 1'h0 ; */ + +/* Description: + * 0: WS should be 0 when sending left channel data, and WS is 1 in + * right channel. + * 1: WS should be 1 when sending left channel data, and WS is 0 in + * right channel. + */ + +#define I2S_TX_WS_IDLE_POL (BIT(17)) +#define I2S_TX_WS_IDLE_POL_M (BIT(17)) +#define I2S_TX_WS_IDLE_POL_V 0x1 +#define I2S_TX_WS_IDLE_POL_S 17 + +/* I2S_TX_24_FILL_EN : R/W ;bitpos:[16] ;default: 1'h0 ; */ + +/* Description: + * 1: Sent 32 bits in 24 channel bits mode. + * 0: Sent 24 bits in 24 channel bits mode. + */ + +#define I2S_TX_24_FILL_EN (BIT(16)) +#define I2S_TX_24_FILL_EN_M (BIT(16)) +#define I2S_TX_24_FILL_EN_V 0x1 +#define I2S_TX_24_FILL_EN_S 16 + +/* I2S_TX_LEFT_ALIGN : R/W ;bitpos:[15] ;default: 1'h1 ; */ + +/* Description: 1: I2S TX left alignment mode. 0: I2S TX right + * alignment mode. + */ + +#define I2S_TX_LEFT_ALIGN (BIT(15)) +#define I2S_TX_LEFT_ALIGN_M (BIT(15)) +#define I2S_TX_LEFT_ALIGN_V 0x1 +#define I2S_TX_LEFT_ALIGN_S 15 + +/* I2S_TX_STOP_EN : R/W ;bitpos:[13] ;default: 1'h1 ; */ + +/* Description: Set this bit to stop disable output BCK signal and WS + * signal when tx FIFO is emtpy. + */ + +#define I2S_TX_STOP_EN (BIT(13)) +#define I2S_TX_STOP_EN_M (BIT(13)) +#define I2S_TX_STOP_EN_V 0x1 +#define I2S_TX_STOP_EN_S 13 + +/* I2S_TX_PCM_BYPASS : R/W ;bitpos:[12] ;default: 1'h1 ; */ + +/* Description: Set this bit to bypass Compress/Decompress module for + * transmitted data. + */ + +#define I2S_TX_PCM_BYPASS (BIT(12)) +#define I2S_TX_PCM_BYPASS_M (BIT(12)) +#define I2S_TX_PCM_BYPASS_V 0x1 +#define I2S_TX_PCM_BYPASS_S 12 + +/* I2S_TX_PCM_CONF : R/W ;bitpos:[11:10] ;default: 2'h0 ; */ + +/* Description: I2S TX compress/decompress configuration bit. + * 0 (atol): A-Law decompress, + * 1 (ltoa) : A-Law compress, + * 2 (utol) : u-Law decompress, + * 3 (ltou) : u-Law compress. + */ + +#define I2S_TX_PCM_CONF 0x00000003 +#define I2S_TX_PCM_CONF_M ((I2S_TX_PCM_CONF_V)<<(I2S_TX_PCM_CONF_S)) +#define I2S_TX_PCM_CONF_V 0x3 +#define I2S_TX_PCM_CONF_S 10 + +/* I2S_TX_MONO_FST_VLD : R/W ;bitpos:[9] ;default: 1'b1 ; */ + +/* Description: + * 1: The first channel data value is valid in I2S TX mono mode. + * 0: The second channel data value is valid in I2S TX mono mode. + */ + +#define I2S_TX_MONO_FST_VLD (BIT(9)) +#define I2S_TX_MONO_FST_VLD_M (BIT(9)) +#define I2S_TX_MONO_FST_VLD_V 0x1 +#define I2S_TX_MONO_FST_VLD_S 9 + +/* I2S_TX_UPDATE : R/W/SC ;bitpos:[8] ;default: 1'b0 ; */ + +/* Description: + * Set 1 to update I2S TX registers from APB clock domain to I2S TX + * clock domain. This bit will be cleared by hardware after update + * register done. + */ + +#define I2S_TX_UPDATE (BIT(8)) +#define I2S_TX_UPDATE_M (BIT(8)) +#define I2S_TX_UPDATE_V 0x1 +#define I2S_TX_UPDATE_S 8 + +/* I2S_TX_BIG_ENDIAN : R/W ;bitpos:[7] ;default: 1'b0 ; */ + +/* Description: I2S Tx byte endian, + * 1: low addr value to high addr. + * 0: low addr with low addr value. + */ + +#define I2S_TX_BIG_ENDIAN (BIT(7)) +#define I2S_TX_BIG_ENDIAN_M (BIT(7)) +#define I2S_TX_BIG_ENDIAN_V 0x1 +#define I2S_TX_BIG_ENDIAN_S 7 + +/* I2S_TX_CHAN_EQUAL : R/W ;bitpos:[6] ;default: 1'b0 ; */ + +/* Description: + * 1: The value of Left channel data is equal to the value of right + * channel data in I2S TX mono mode or TDM channel select mode. + * 0: The invalid channel data is reg_i2s_single_data in I2S TX mono + * mode or TDM channel select mode. + */ + +#define I2S_TX_CHAN_EQUAL (BIT(6)) +#define I2S_TX_CHAN_EQUAL_M (BIT(6)) +#define I2S_TX_CHAN_EQUAL_V 0x1 +#define I2S_TX_CHAN_EQUAL_S 6 + +/* I2S_TX_MONO : R/W ;bitpos:[5] ;default: 1'b0 ; */ + +/* Description: Set this bit to enable transmitter in mono mode. */ + +#define I2S_TX_MONO (BIT(5)) +#define I2S_TX_MONO_M (BIT(5)) +#define I2S_TX_MONO_V 0x1 +#define I2S_TX_MONO_S 5 + +/* I2S_TX_SLAVE_MOD : R/W ;bitpos:[3] ;default: 1'b0 ; */ + +/* Description: Set this bit to enable slave transmitter mode. */ + +#define I2S_TX_SLAVE_MOD (BIT(3)) +#define I2S_TX_SLAVE_MOD_M (BIT(3)) +#define I2S_TX_SLAVE_MOD_V 0x1 +#define I2S_TX_SLAVE_MOD_S 3 + +/* I2S_TX_START : R/W ;bitpos:[2] ;default: 1'b0 ; */ + +/* Description: Set this bit to start transmitting data. */ + +#define I2S_TX_START (BIT(2)) +#define I2S_TX_START_M (BIT(2)) +#define I2S_TX_START_V 0x1 +#define I2S_TX_START_S 2 + +/* I2S_TX_FIFO_RESET : WT ;bitpos:[1] ;default: 1'b0 ; */ + +/* Description: Set this bit to reset Tx AFIFO. */ + +#define I2S_TX_FIFO_RESET (BIT(1)) +#define I2S_TX_FIFO_RESET_M (BIT(1)) +#define I2S_TX_FIFO_RESET_V 0x1 +#define I2S_TX_FIFO_RESET_S 1 + +/* I2S_TX_RESET : WT ;bitpos:[0] ;default: 1'b0 ; */ + +/* Description: Set this bit to reset transmitter. */ + +#define I2S_TX_RESET (BIT(0)) +#define I2S_TX_RESET_M (BIT(0)) +#define I2S_TX_RESET_V 0x1 +#define I2S_TX_RESET_S 0 + +#define I2S_RX_CONF1_REG(i) (REG_I2S_BASE(i) + 0x28) + +/* I2S_RX_MSB_SHIFT : R/W ;bitpos:[29] ;default: 1'b1 ; */ + +/* Description: Set this bit to enable receiver in Phillips + * standard mode. + */ + +#define I2S_RX_MSB_SHIFT (BIT(29)) +#define I2S_RX_MSB_SHIFT_M (BIT(29)) +#define I2S_RX_MSB_SHIFT_V 0x1 +#define I2S_RX_MSB_SHIFT_S 29 + +/* I2S_RX_TDM_CHAN_BITS : R/W ;bitpos:[28:24] ;default: 5'hf ; */ + +/* Description: The Rx bit number for each channel minus 1in TDM mode. */ + +#define I2S_RX_TDM_CHAN_BITS 0x0000001F +#define I2S_RX_TDM_CHAN_BITS_M ((I2S_RX_TDM_CHAN_BITS_V)<<(I2S_RX_TDM_CHAN_BITS_S)) +#define I2S_RX_TDM_CHAN_BITS_V 0x1F +#define I2S_RX_TDM_CHAN_BITS_S 24 + +/* I2S_RX_HALF_SAMPLE_BITS : R/W ;bitpos:[23:18] ;default: 6'hf ; */ + +/* Description: I2S Rx half sample bits -1. */ + +#define I2S_RX_HALF_SAMPLE_BITS 0x0000003F +#define I2S_RX_HALF_SAMPLE_BITS_M ((I2S_RX_HALF_SAMPLE_BITS_V)<<(I2S_RX_HALF_SAMPLE_BITS_S)) +#define I2S_RX_HALF_SAMPLE_BITS_V 0x3F +#define I2S_RX_HALF_SAMPLE_BITS_S 18 + +/* I2S_RX_BITS_MOD : R/W ;bitpos:[17:13] ;default: 5'hf ; */ + +/* Description: Set the bits to configure the valid data bit length + * of I2S receiver channel. + * 7: all the valid channel data is in 8-bit-mode. + * 15: all the valid channel data is in 16-bit-mode. + * 23: all the valid channel data is in 24-bit-mode. + * 31:all the valid channel data is in 32-bit-mode. + */ + +#define I2S_RX_BITS_MOD 0x0000001F +#define I2S_RX_BITS_MOD_M ((I2S_RX_BITS_MOD_V)<<(I2S_RX_BITS_MOD_S)) +#define I2S_RX_BITS_MOD_V 0x1F +#define I2S_RX_BITS_MOD_S 13 + +/* I2S_RX_BCK_DIV_NUM : R/W ;bitpos:[12:7] ;default: 6'd6 ; */ + +/* Description: Bit clock configuration bits in receiver mode. */ + +#define I2S_RX_BCK_DIV_NUM 0x0000003F +#define I2S_RX_BCK_DIV_NUM_M ((I2S_RX_BCK_DIV_NUM_V)<<(I2S_RX_BCK_DIV_NUM_S)) +#define I2S_RX_BCK_DIV_NUM_V 0x3F +#define I2S_RX_BCK_DIV_NUM_S 7 + +/* I2S_RX_TDM_WS_WIDTH : R/W ;bitpos:[6:0] ;default: 7'h0 ; */ + +/* Description: The width of rx_ws_out in TDM mode is + * (I2S_RX_TDM_WS_WIDTH[6:0] +1) * T_bck. + */ + +#define I2S_RX_TDM_WS_WIDTH 0x0000007F +#define I2S_RX_TDM_WS_WIDTH_M ((I2S_RX_TDM_WS_WIDTH_V)<<(I2S_RX_TDM_WS_WIDTH_S)) +#define I2S_RX_TDM_WS_WIDTH_V 0x7F +#define I2S_RX_TDM_WS_WIDTH_S 0 + +#define I2S_TX_CONF1_REG(i) (REG_I2S_BASE(i) + 0x2C) + +/* I2S_TX_BCK_NO_DLY : R/W ;bitpos:[30] ;default: 1'b1 ; */ + +/* Description: + * 1: BCK is not delayed to generate pos/neg edge in master mode. + * 0: BCK is delayed to generate pos/neg edge in master mode. + */ + +#define I2S_TX_BCK_NO_DLY (BIT(30)) +#define I2S_TX_BCK_NO_DLY_M (BIT(30)) +#define I2S_TX_BCK_NO_DLY_V 0x1 +#define I2S_TX_BCK_NO_DLY_S 30 + +/* I2S_TX_MSB_SHIFT : R/W ;bitpos:[29] ;default: 1'b1 ; */ + +/* Description: Set this bit to enable transmitter in Phillips + * standard mode. + */ + +#define I2S_TX_MSB_SHIFT (BIT(29)) +#define I2S_TX_MSB_SHIFT_M (BIT(29)) +#define I2S_TX_MSB_SHIFT_V 0x1 +#define I2S_TX_MSB_SHIFT_S 29 + +/* I2S_TX_TDM_CHAN_BITS : R/W ;bitpos:[28:24] ;default: 5'hf ; */ + +/* Description: The Tx bit number for each channel minus 1in TDM mode. */ + +#define I2S_TX_TDM_CHAN_BITS 0x0000001F +#define I2S_TX_TDM_CHAN_BITS_M ((I2S_TX_TDM_CHAN_BITS_V)<<(I2S_TX_TDM_CHAN_BITS_S)) +#define I2S_TX_TDM_CHAN_BITS_V 0x1F +#define I2S_TX_TDM_CHAN_BITS_S 24 + +/* I2S_TX_HALF_SAMPLE_BITS : R/W ;bitpos:[23:18] ;default: 6'hf ; */ + +/* Description: I2S Tx half sample bits -1. */ + +#define I2S_TX_HALF_SAMPLE_BITS 0x0000003F +#define I2S_TX_HALF_SAMPLE_BITS_M ((I2S_TX_HALF_SAMPLE_BITS_V)<<(I2S_TX_HALF_SAMPLE_BITS_S)) +#define I2S_TX_HALF_SAMPLE_BITS_V 0x3F +#define I2S_TX_HALF_SAMPLE_BITS_S 18 + +/* I2S_TX_BITS_MOD : R/W ;bitpos:[17:13] ;default: 5'hf ; */ + +/* Description: + * Set the bits to configure the valid data bit length of I2S transmitter + * channel. + * 7: all the valid channel data is in 8-bit-mode. + * 15: all the valid channel data is in 16-bit-mode. + * 23: all the valid channel data is in 24-bit-mode. + * 31:all the valid channel data is in 32-bit-mode. + */ + +#define I2S_TX_BITS_MOD 0x0000001F +#define I2S_TX_BITS_MOD_M ((I2S_TX_BITS_MOD_V)<<(I2S_TX_BITS_MOD_S)) +#define I2S_TX_BITS_MOD_V 0x1F +#define I2S_TX_BITS_MOD_S 13 + +/* I2S_TX_BCK_DIV_NUM : R/W ;bitpos:[12:7] ;default: 6'd6 ; */ + +/* Description: Bit clock configuration bits in transmitter mode. */ + +#define I2S_TX_BCK_DIV_NUM 0x0000003F +#define I2S_TX_BCK_DIV_NUM_M ((I2S_TX_BCK_DIV_NUM_V)<<(I2S_TX_BCK_DIV_NUM_S)) +#define I2S_TX_BCK_DIV_NUM_V 0x3F +#define I2S_TX_BCK_DIV_NUM_S 7 + +/* I2S_TX_TDM_WS_WIDTH : R/W ;bitpos:[6:0] ;default: 7'h0 ; */ + +/* Description: + * The width of tx_ws_out in TDM mode is: + * (I2S_TX_TDM_WS_WIDTH[6:0] +1) * T_bck. + */ + +#define I2S_TX_TDM_WS_WIDTH 0x0000007F +#define I2S_TX_TDM_WS_WIDTH_M ((I2S_TX_TDM_WS_WIDTH_V)<<(I2S_TX_TDM_WS_WIDTH_S)) +#define I2S_TX_TDM_WS_WIDTH_V 0x7F +#define I2S_TX_TDM_WS_WIDTH_S 0 + +#define I2S_RX_CLKM_CONF_REG(i) (REG_I2S_BASE(i) + 0x30) + +/* I2S_MCLK_SEL : R/W ;bitpos:[29] ;default: 1'b0 ; */ + +/* Description: + * 0: Use I2S Tx module clock as I2S_MCLK_OUT. + * 1: Use I2S Rx module clock as I2S_MCLK_OUT. + */ + +#define I2S_MCLK_SEL (BIT(29)) +#define I2S_MCLK_SEL_M (BIT(29)) +#define I2S_MCLK_SEL_V 0x1 +#define I2S_MCLK_SEL_S 29 + +/* I2S_RX_CLK_SEL : R/W ;bitpos:[28:27] ;default: 2'b0 ; */ + +/* Description: + * Select I2S Rx module source clock. + * 0: no clock. + * 1: APLL. + * 2: CLK160, + * 3: I2S_MCLK_in. + */ + +#define I2S_RX_CLK_SEL 0x00000003 +#define I2S_RX_CLK_SEL_M ((I2S_RX_CLK_SEL_V)<<(I2S_RX_CLK_SEL_S)) +#define I2S_RX_CLK_SEL_V 0x3 +#define I2S_RX_CLK_SEL_S 27 + +/* I2S_RX_CLK_ACTIVE : R/W ;bitpos:[26] ;default: 1'b0 ; */ + +/* Description: I2S Rx module clock enable signal. */ + +#define I2S_RX_CLK_ACTIVE (BIT(26)) +#define I2S_RX_CLK_ACTIVE_M (BIT(26)) +#define I2S_RX_CLK_ACTIVE_V 0x1 +#define I2S_RX_CLK_ACTIVE_S 26 + +/* I2S_RX_CLKM_DIV_NUM : R/W ;bitpos:[7:0] ;default: 8'd2 ; */ + +/* Description: Integral I2S clock divider value. */ + +#define I2S_RX_CLKM_DIV_NUM 0x000000FF +#define I2S_RX_CLKM_DIV_NUM_M ((I2S_RX_CLKM_DIV_NUM_V)<<(I2S_RX_CLKM_DIV_NUM_S)) +#define I2S_RX_CLKM_DIV_NUM_V 0xFF +#define I2S_RX_CLKM_DIV_NUM_S 0 + +#define I2S_TX_CLKM_CONF_REG(i) (REG_I2S_BASE(i) + 0x34) + +/* I2S_CLK_EN : R/W ;bitpos:[29] ;default: 1'b0 ; */ + +/* Description: Set this bit to enable clk gate. */ + +#define I2S_CLK_EN (BIT(29)) +#define I2S_CLK_EN_M (BIT(29)) +#define I2S_CLK_EN_V 0x1 +#define I2S_CLK_EN_S 29 + +/* I2S_TX_CLK_SEL : R/W ;bitpos:[28:27] ;default: 2'b0 ; */ + +/* Description: + * Select I2S Tx module source clock. + * 0: XTAL clock. + * 1: APLL. + * 2: CLK160. + * 3: I2S_MCLK_in. + */ + +#define I2S_TX_CLK_SEL 0x00000003 +#define I2S_TX_CLK_SEL_M ((I2S_TX_CLK_SEL_V)<<(I2S_TX_CLK_SEL_S)) +#define I2S_TX_CLK_SEL_V 0x3 +#define I2S_TX_CLK_SEL_S 27 + +/* I2S_TX_CLK_ACTIVE : R/W ;bitpos:[26] ;default: 1'b0 ; */ + +/* Description: I2S Tx module clock enable signal. */ + +#define I2S_TX_CLK_ACTIVE (BIT(26)) +#define I2S_TX_CLK_ACTIVE_M (BIT(26)) +#define I2S_TX_CLK_ACTIVE_V 0x1 +#define I2S_TX_CLK_ACTIVE_S 26 + +/* I2S_TX_CLKM_DIV_NUM : R/W ;bitpos:[7:0] ;default: 8'd2 ; */ + +/* Description: + * Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). + * There will be (a-b) * n-div and b * (n+1)-div. So the average combination + * will be: for b <= a/2, z * [x * n-div + (n+1)-div] + y * n-div. + * For b > a/2, z * [n-div + x * (n+1)-div] + y * (n+1)-div. + */ + +#define I2S_TX_CLKM_DIV_NUM 0x000000FF +#define I2S_TX_CLKM_DIV_NUM_M ((I2S_TX_CLKM_DIV_NUM_V)<<(I2S_TX_CLKM_DIV_NUM_S)) +#define I2S_TX_CLKM_DIV_NUM_V 0xFF +#define I2S_TX_CLKM_DIV_NUM_S 0 + +#define I2S_RX_CLKM_DIV_CONF_REG(i) (REG_I2S_BASE(i) + 0x38) + +/* I2S_RX_CLKM_DIV_YN1 : R/W ;bitpos:[27] ;default: 1'b0 ; */ + +/* Description: + * For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0. + * For b > a/2, the value of I2S_RX_CLKM_DIV_YN1 is 1. + */ + +#define I2S_RX_CLKM_DIV_YN1 (BIT(27)) +#define I2S_RX_CLKM_DIV_YN1_M (BIT(27)) +#define I2S_RX_CLKM_DIV_YN1_V 0x1 +#define I2S_RX_CLKM_DIV_YN1_S 27 + +/* I2S_RX_CLKM_DIV_X : R/W ;bitpos:[26:18] ;default: 9'h0 ; */ + +/* Description: + * For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. + * For b > a/2, the value of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1. + */ + +#define I2S_RX_CLKM_DIV_X 0x000001FF +#define I2S_RX_CLKM_DIV_X_M ((I2S_RX_CLKM_DIV_X_V)<<(I2S_RX_CLKM_DIV_X_S)) +#define I2S_RX_CLKM_DIV_X_V 0x1FF +#define I2S_RX_CLKM_DIV_X_S 18 + +/* I2S_RX_CLKM_DIV_Y : R/W ;bitpos:[17:9] ;default: 9'h1 ; */ + +/* Description: + * For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b). + * For b > a/2, the value of I2S_RX_CLKM_DIV_Y is (a%(a-b)). + */ + +#define I2S_RX_CLKM_DIV_Y 0x000001FF +#define I2S_RX_CLKM_DIV_Y_M ((I2S_RX_CLKM_DIV_Y_V)<<(I2S_RX_CLKM_DIV_Y_S)) +#define I2S_RX_CLKM_DIV_Y_V 0x1FF +#define I2S_RX_CLKM_DIV_Y_S 9 + +/* I2S_RX_CLKM_DIV_Z : R/W ;bitpos:[8:0] ;default: 9'h0 ; */ + +/* Description: + * For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. + * For b > a/2, the value of I2S_RX_CLKM_DIV_Z is (a-b). + */ + +#define I2S_RX_CLKM_DIV_Z 0x000001FF +#define I2S_RX_CLKM_DIV_Z_M ((I2S_RX_CLKM_DIV_Z_V)<<(I2S_RX_CLKM_DIV_Z_S)) +#define I2S_RX_CLKM_DIV_Z_V 0x1FF +#define I2S_RX_CLKM_DIV_Z_S 0 + +#define I2S_TX_CLKM_DIV_CONF_REG(i) (REG_I2S_BASE(i) + 0x3C) + +/* I2S_TX_CLKM_DIV_YN1 : R/W ;bitpos:[27] ;default: 1'b0 ; */ + +/* Description: For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0. + * For b > a/2, the value of I2S_TX_CLKM_DIV_YN1 is 1. + */ + +#define I2S_TX_CLKM_DIV_YN1 (BIT(27)) +#define I2S_TX_CLKM_DIV_YN1_M (BIT(27)) +#define I2S_TX_CLKM_DIV_YN1_V 0x1 +#define I2S_TX_CLKM_DIV_YN1_S 27 + +/* I2S_TX_CLKM_DIV_X : R/W ;bitpos:[26:18] ;default: 9'h0 ; */ + +/* Description: + * For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. + * For b > a/2, the value of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1. + */ + +#define I2S_TX_CLKM_DIV_X 0x000001FF +#define I2S_TX_CLKM_DIV_X_M ((I2S_TX_CLKM_DIV_X_V)<<(I2S_TX_CLKM_DIV_X_S)) +#define I2S_TX_CLKM_DIV_X_V 0x1FF +#define I2S_TX_CLKM_DIV_X_S 18 + +/* I2S_TX_CLKM_DIV_Y : R/W ;bitpos:[17:9] ;default: 9'h1 ; */ + +/* Description: For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b). + * For b > a/2, the value of I2S_TX_CLKM_DIV_Y is (a%(a-b)). + */ + +#define I2S_TX_CLKM_DIV_Y 0x000001FF +#define I2S_TX_CLKM_DIV_Y_M ((I2S_TX_CLKM_DIV_Y_V)<<(I2S_TX_CLKM_DIV_Y_S)) +#define I2S_TX_CLKM_DIV_Y_V 0x1FF +#define I2S_TX_CLKM_DIV_Y_S 9 + +/* I2S_TX_CLKM_DIV_Z : R/W ;bitpos:[8:0] ;default: 9'h0 ; */ + +/* Description: For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. + * For b > a/2, the value of I2S_TX_CLKM_DIV_Z is (a-b). + */ + +#define I2S_TX_CLKM_DIV_Z 0x000001FF +#define I2S_TX_CLKM_DIV_Z_M ((I2S_TX_CLKM_DIV_Z_V)<<(I2S_TX_CLKM_DIV_Z_S)) +#define I2S_TX_CLKM_DIV_Z_V 0x1FF +#define I2S_TX_CLKM_DIV_Z_S 0 + +#define I2S_TX_PCM2PDM_CONF_REG(i) (REG_I2S_BASE(i) + 0x40) + +/* I2S_PCM2PDM_CONV_EN : R/W ;bitpos:[25] ;default: 1'b0 ; */ + +/* Description: I2S TX PDM Converter enable. */ + +#define I2S_PCM2PDM_CONV_EN (BIT(25)) +#define I2S_PCM2PDM_CONV_EN_M (BIT(25)) +#define I2S_PCM2PDM_CONV_EN_V 0x1 +#define I2S_PCM2PDM_CONV_EN_S 25 + +/* I2S_TX_PDM_DAC_MODE_EN : R/W ;bitpos:[24] ;default: 1'b0 ; */ + +/* Description: I2S TX PDM dac 2channel enable. */ + +#define I2S_TX_PDM_DAC_MODE_EN (BIT(24)) +#define I2S_TX_PDM_DAC_MODE_EN_M (BIT(24)) +#define I2S_TX_PDM_DAC_MODE_EN_V 0x1 +#define I2S_TX_PDM_DAC_MODE_EN_S 24 + +/* I2S_TX_PDM_DAC_2OUT_EN : R/W ;bitpos:[23] ;default: 1'b0 ; */ + +/* Description: I2S TX PDM dac mode enable. */ + +#define I2S_TX_PDM_DAC_2OUT_EN (BIT(23)) +#define I2S_TX_PDM_DAC_2OUT_EN_M (BIT(23)) +#define I2S_TX_PDM_DAC_2OUT_EN_V 0x1 +#define I2S_TX_PDM_DAC_2OUT_EN_S 23 + +/* I2S_TX_PDM_SIGMADELTA_DITHER : R/W ;bitpos:[22] ;default: 1'b1 ; */ + +/* Description: I2S TX PDM sigmadelta dither value. */ + +#define I2S_TX_PDM_SIGMADELTA_DITHER (BIT(22)) +#define I2S_TX_PDM_SIGMADELTA_DITHER_M (BIT(22)) +#define I2S_TX_PDM_SIGMADELTA_DITHER_V 0x1 +#define I2S_TX_PDM_SIGMADELTA_DITHER_S 22 + +/* I2S_TX_PDM_SIGMADELTA_DITHER2 : R/W ;bitpos:[21] ;default: 1'b0 ; */ + +/* Description: I2S TX PDM sigmadelta dither2 value. */ + +#define I2S_TX_PDM_SIGMADELTA_DITHER2 (BIT(21)) +#define I2S_TX_PDM_SIGMADELTA_DITHER2_M (BIT(21)) +#define I2S_TX_PDM_SIGMADELTA_DITHER2_V 0x1 +#define I2S_TX_PDM_SIGMADELTA_DITHER2_S 21 + +/* I2S_TX_PDM_SIGMADELTA_IN_SHIFT : R/W ;bitpos:[20:19] ;default: 2'h1 ; */ + +/* Description: I2S TX PDM sigmadelta scale shift number: + * 0: /2, + * 1: x1, + * 2: x2, + * 3: x4. + */ + +#define I2S_TX_PDM_SIGMADELTA_IN_SHIFT 0x00000003 +#define I2S_TX_PDM_SIGMADELTA_IN_SHIFT_M ((I2S_TX_PDM_SIGMADELTA_IN_SHIFT_V)<<(I2S_TX_PDM_SIGMADELTA_IN_SHIFT_S)) +#define I2S_TX_PDM_SIGMADELTA_IN_SHIFT_V 0x3 +#define I2S_TX_PDM_SIGMADELTA_IN_SHIFT_S 19 + +/* I2S_TX_PDM_SINC_IN_SHIFT : R/W ;bitpos:[18:17] ;default: 2'h1 ; */ + +/* Description: I2S TX PDM sigmadelta scale shift number: + * 0: /2, + * 1: x1, + * 2: x2, + * 3: x4. + */ + +#define I2S_TX_PDM_SINC_IN_SHIFT 0x00000003 +#define I2S_TX_PDM_SINC_IN_SHIFT_M ((I2S_TX_PDM_SINC_IN_SHIFT_V)<<(I2S_TX_PDM_SINC_IN_SHIFT_S)) +#define I2S_TX_PDM_SINC_IN_SHIFT_V 0x3 +#define I2S_TX_PDM_SINC_IN_SHIFT_S 17 + +/* I2S_TX_PDM_LP_IN_SHIFT : R/W ;bitpos:[16:15] ;default: 2'h1 ; */ + +/* Description: I2S TX PDM sigmadelta scale shift number: + * 0: /2, + * 1: x1, + * 2: x2, + * 3: x4. + */ + +#define I2S_TX_PDM_LP_IN_SHIFT 0x00000003 +#define I2S_TX_PDM_LP_IN_SHIFT_M ((I2S_TX_PDM_LP_IN_SHIFT_V)<<(I2S_TX_PDM_LP_IN_SHIFT_S)) +#define I2S_TX_PDM_LP_IN_SHIFT_V 0x3 +#define I2S_TX_PDM_LP_IN_SHIFT_S 15 + +/* I2S_TX_PDM_HP_IN_SHIFT : R/W ;bitpos:[14:13] ;default: 2'h1 ; */ + +/* Description: I2S TX PDM sigmadelta scale shift number: + * 0: /2, + * 1: x1, + * 2: x2, + * 3: x4. + */ + +#define I2S_TX_PDM_HP_IN_SHIFT 0x00000003 +#define I2S_TX_PDM_HP_IN_SHIFT_M ((I2S_TX_PDM_HP_IN_SHIFT_V)<<(I2S_TX_PDM_HP_IN_SHIFT_S)) +#define I2S_TX_PDM_HP_IN_SHIFT_V 0x3 +#define I2S_TX_PDM_HP_IN_SHIFT_S 13 + +/* I2S_TX_PDM_PRESCALE : R/W ;bitpos:[12:5] ;default: 8'h0 ; */ + +/* Description: I2S TX PDM prescale for sigmadelta. */ + +#define I2S_TX_PDM_PRESCALE 0x000000FF +#define I2S_TX_PDM_PRESCALE_M ((I2S_TX_PDM_PRESCALE_V)<<(I2S_TX_PDM_PRESCALE_S)) +#define I2S_TX_PDM_PRESCALE_V 0xFF +#define I2S_TX_PDM_PRESCALE_S 5 + +/* I2S_TX_PDM_SINC_OSR2 : R/W ;bitpos:[4:1] ;default: 4'h2 ; */ + +/* Description: I2S TX PDM OSR2 value. */ + +#define I2S_TX_PDM_SINC_OSR2 0x0000000F +#define I2S_TX_PDM_SINC_OSR2_M ((I2S_TX_PDM_SINC_OSR2_V)<<(I2S_TX_PDM_SINC_OSR2_S)) +#define I2S_TX_PDM_SINC_OSR2_V 0xF +#define I2S_TX_PDM_SINC_OSR2_S 1 + +/* I2S_TX_PDM_HP_BYPASS : R/W ;bitpos:[0] ;default: 1'b0 ; */ + +/* Description: I2S TX PDM bypass hp filter or not. + * The option has been removed. + */ + +#define I2S_TX_PDM_HP_BYPASS (BIT(0)) +#define I2S_TX_PDM_HP_BYPASS_M (BIT(0)) +#define I2S_TX_PDM_HP_BYPASS_V 0x1 +#define I2S_TX_PDM_HP_BYPASS_S 0 + +#define I2S_TX_PCM2PDM_CONF1_REG(i) (REG_I2S_BASE(i) + 0x44) + +/* I2S_TX_IIR_HP_MULT12_0 : R/W ;bitpos:[25:23] ;default: 3'd7 ; */ + +/* Description: The fourth parameter of PDM TX IIR_HP filter stage 1 + * is (504 + I2S_TX_IIR_HP_MULT12_0[2:0]). + */ + +#define I2S_TX_IIR_HP_MULT12_0 0x00000007 +#define I2S_TX_IIR_HP_MULT12_0_M ((I2S_TX_IIR_HP_MULT12_0_V)<<(I2S_TX_IIR_HP_MULT12_0_S)) +#define I2S_TX_IIR_HP_MULT12_0_V 0x7 +#define I2S_TX_IIR_HP_MULT12_0_S 23 + +/* I2S_TX_IIR_HP_MULT12_5 : R/W ;bitpos:[22:20] ;default: 3'd7 ; */ + +/* Description: The fourth parameter of PDM TX IIR_HP filter stage 2 + * is (504 + I2S_TX_IIR_HP_MULT12_5[2:0]). + */ + +#define I2S_TX_IIR_HP_MULT12_5 0x00000007 +#define I2S_TX_IIR_HP_MULT12_5_M ((I2S_TX_IIR_HP_MULT12_5_V)<<(I2S_TX_IIR_HP_MULT12_5_S)) +#define I2S_TX_IIR_HP_MULT12_5_V 0x7 +#define I2S_TX_IIR_HP_MULT12_5_S 20 + +/* I2S_TX_PDM_FS : R/W ;bitpos:[19:10] ;default: 10'd480 ; */ + +/* Description: I2S TX PDM Fs. */ + +#define I2S_TX_PDM_FS 0x000003FF +#define I2S_TX_PDM_FS_M ((I2S_TX_PDM_FS_V)<<(I2S_TX_PDM_FS_S)) +#define I2S_TX_PDM_FS_V 0x3FF +#define I2S_TX_PDM_FS_S 10 + +/* I2S_TX_PDM_FP : R/W ;bitpos:[9:0] ;default: 10'd960 ; */ + +/* Description: I2S TX PDM Fp. */ + +#define I2S_TX_PDM_FP 0x000003FF +#define I2S_TX_PDM_FP_M ((I2S_TX_PDM_FP_V)<<(I2S_TX_PDM_FP_S)) +#define I2S_TX_PDM_FP_V 0x3FF +#define I2S_TX_PDM_FP_S 0 + +#define I2S_RX_TDM_CTRL_REG(i) (REG_I2S_BASE(i) + 0x50) + +/* I2S_RX_TDM_TOT_CHAN_NUM : R/W ;bitpos:[19:16] ;default: 4'h0 ; */ + +/* Description: The total channel number of I2S TX TDM mode. */ + +#define I2S_RX_TDM_TOT_CHAN_NUM 0x0000000F +#define I2S_RX_TDM_TOT_CHAN_NUM_M ((I2S_RX_TDM_TOT_CHAN_NUM_V)<<(I2S_RX_TDM_TOT_CHAN_NUM_S)) +#define I2S_RX_TDM_TOT_CHAN_NUM_V 0xF +#define I2S_RX_TDM_TOT_CHAN_NUM_S 16 + +/* I2S_RX_TDM_CHAN15_EN : R/W ;bitpos:[15] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_CHAN15_EN (BIT(15)) +#define I2S_RX_TDM_CHAN15_EN_M (BIT(15)) +#define I2S_RX_TDM_CHAN15_EN_V 0x1 +#define I2S_RX_TDM_CHAN15_EN_S 15 + +/* I2S_RX_TDM_CHAN14_EN : R/W ;bitpos:[14] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_CHAN14_EN (BIT(14)) +#define I2S_RX_TDM_CHAN14_EN_M (BIT(14)) +#define I2S_RX_TDM_CHAN14_EN_V 0x1 +#define I2S_RX_TDM_CHAN14_EN_S 14 + +/* I2S_RX_TDM_CHAN13_EN : R/W ;bitpos:[13] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_CHAN13_EN (BIT(13)) +#define I2S_RX_TDM_CHAN13_EN_M (BIT(13)) +#define I2S_RX_TDM_CHAN13_EN_V 0x1 +#define I2S_RX_TDM_CHAN13_EN_S 13 + +/* I2S_RX_TDM_CHAN12_EN : R/W ;bitpos:[12] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_CHAN12_EN (BIT(12)) +#define I2S_RX_TDM_CHAN12_EN_M (BIT(12)) +#define I2S_RX_TDM_CHAN12_EN_V 0x1 +#define I2S_RX_TDM_CHAN12_EN_S 12 + +/* I2S_RX_TDM_CHAN11_EN : R/W ;bitpos:[11] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_CHAN11_EN (BIT(11)) +#define I2S_RX_TDM_CHAN11_EN_M (BIT(11)) +#define I2S_RX_TDM_CHAN11_EN_V 0x1 +#define I2S_RX_TDM_CHAN11_EN_S 11 + +/* I2S_RX_TDM_CHAN10_EN : R/W ;bitpos:[10] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_CHAN10_EN (BIT(10)) +#define I2S_RX_TDM_CHAN10_EN_M (BIT(10)) +#define I2S_RX_TDM_CHAN10_EN_V 0x1 +#define I2S_RX_TDM_CHAN10_EN_S 10 + +/* I2S_RX_TDM_CHAN9_EN : R/W ;bitpos:[9] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_CHAN9_EN (BIT(9)) +#define I2S_RX_TDM_CHAN9_EN_M (BIT(9)) +#define I2S_RX_TDM_CHAN9_EN_V 0x1 +#define I2S_RX_TDM_CHAN9_EN_S 9 + +/* I2S_RX_TDM_CHAN8_EN : R/W ;bitpos:[8] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM channel $n. + * 0: Disable, just input 0 in this channel.. + */ + +#define I2S_RX_TDM_CHAN8_EN (BIT(8)) +#define I2S_RX_TDM_CHAN8_EN_M (BIT(8)) +#define I2S_RX_TDM_CHAN8_EN_V 0x1 +#define I2S_RX_TDM_CHAN8_EN_S 8 + +/* I2S_RX_TDM_PDM_CHAN7_EN : R/W ;bitpos:[7] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel.. + */ + +#define I2S_RX_TDM_PDM_CHAN7_EN (BIT(7)) +#define I2S_RX_TDM_PDM_CHAN7_EN_M (BIT(7)) +#define I2S_RX_TDM_PDM_CHAN7_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN7_EN_S 7 + +/* I2S_RX_TDM_PDM_CHAN6_EN : R/W ;bitpos:[6] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_PDM_CHAN6_EN (BIT(6)) +#define I2S_RX_TDM_PDM_CHAN6_EN_M (BIT(6)) +#define I2S_RX_TDM_PDM_CHAN6_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN6_EN_S 6 + +/* I2S_RX_TDM_PDM_CHAN5_EN : R/W ;bitpos:[5] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_PDM_CHAN5_EN (BIT(5)) +#define I2S_RX_TDM_PDM_CHAN5_EN_M (BIT(5)) +#define I2S_RX_TDM_PDM_CHAN5_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN5_EN_S 5 + +/* I2S_RX_TDM_PDM_CHAN4_EN : R/W ;bitpos:[4] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_PDM_CHAN4_EN (BIT(4)) +#define I2S_RX_TDM_PDM_CHAN4_EN_M (BIT(4)) +#define I2S_RX_TDM_PDM_CHAN4_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN4_EN_S 4 + +/* I2S_RX_TDM_PDM_CHAN3_EN : R/W ;bitpos:[3] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_PDM_CHAN3_EN (BIT(3)) +#define I2S_RX_TDM_PDM_CHAN3_EN_M (BIT(3)) +#define I2S_RX_TDM_PDM_CHAN3_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN3_EN_S 3 + +/* I2S_RX_TDM_PDM_CHAN2_EN : R/W ;bitpos:[2] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_PDM_CHAN2_EN (BIT(2)) +#define I2S_RX_TDM_PDM_CHAN2_EN_M (BIT(2)) +#define I2S_RX_TDM_PDM_CHAN2_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN2_EN_S 2 + +/* I2S_RX_TDM_PDM_CHAN1_EN : R/W ;bitpos:[1] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_PDM_CHAN1_EN (BIT(1)) +#define I2S_RX_TDM_PDM_CHAN1_EN_M (BIT(1)) +#define I2S_RX_TDM_PDM_CHAN1_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN1_EN_S 1 + +/* I2S_RX_TDM_PDM_CHAN0_EN : R/W ;bitpos:[0] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data input of I2S RX TDM or PDM channel $n. + * 0: Disable, just input 0 in this channel. + */ + +#define I2S_RX_TDM_PDM_CHAN0_EN (BIT(0)) +#define I2S_RX_TDM_PDM_CHAN0_EN_M (BIT(0)) +#define I2S_RX_TDM_PDM_CHAN0_EN_V 0x1 +#define I2S_RX_TDM_PDM_CHAN0_EN_S 0 + +#define I2S_TX_TDM_CTRL_REG(i) (REG_I2S_BASE(i) + 0x54) + +/* I2S_TX_TDM_SKIP_MSK_EN : R/W ;bitpos:[20] ;default: 1'b0 ; */ + +/* Description: + * When DMA TX buffer stores the data of (REG_TX_TDM_TOT_CHAN_NUM + 1) + * channels, and only the data of the enabled channels is sent, then + * this bit should be set. Clear it when all the data stored in DMA TX + * buffer is for enabled channels.. + */ + +#define I2S_TX_TDM_SKIP_MSK_EN (BIT(20)) +#define I2S_TX_TDM_SKIP_MSK_EN_M (BIT(20)) +#define I2S_TX_TDM_SKIP_MSK_EN_V 0x1 +#define I2S_TX_TDM_SKIP_MSK_EN_S 20 + +/* I2S_TX_TDM_TOT_CHAN_NUM : R/W ;bitpos:[19:16] ;default: 4'h0 ; */ + +/* Description: The total channel number of I2S TX TDM mode. */ + +#define I2S_TX_TDM_TOT_CHAN_NUM 0x0000000F +#define I2S_TX_TDM_TOT_CHAN_NUM_M ((I2S_TX_TDM_TOT_CHAN_NUM_V)<<(I2S_TX_TDM_TOT_CHAN_NUM_S)) +#define I2S_TX_TDM_TOT_CHAN_NUM_V 0xF +#define I2S_TX_TDM_TOT_CHAN_NUM_S 16 + +/* I2S_TX_TDM_CHAN15_EN : R/W ;bitpos:[15] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN15_EN (BIT(15)) +#define I2S_TX_TDM_CHAN15_EN_M (BIT(15)) +#define I2S_TX_TDM_CHAN15_EN_V 0x1 +#define I2S_TX_TDM_CHAN15_EN_S 15 + +/* I2S_TX_TDM_CHAN14_EN : R/W ;bitpos:[14] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN14_EN (BIT(14)) +#define I2S_TX_TDM_CHAN14_EN_M (BIT(14)) +#define I2S_TX_TDM_CHAN14_EN_V 0x1 +#define I2S_TX_TDM_CHAN14_EN_S 14 + +/* I2S_TX_TDM_CHAN13_EN : R/W ;bitpos:[13] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN13_EN (BIT(13)) +#define I2S_TX_TDM_CHAN13_EN_M (BIT(13)) +#define I2S_TX_TDM_CHAN13_EN_V 0x1 +#define I2S_TX_TDM_CHAN13_EN_S 13 + +/* I2S_TX_TDM_CHAN12_EN : R/W ;bitpos:[12] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel.. + */ + +#define I2S_TX_TDM_CHAN12_EN (BIT(12)) +#define I2S_TX_TDM_CHAN12_EN_M (BIT(12)) +#define I2S_TX_TDM_CHAN12_EN_V 0x1 +#define I2S_TX_TDM_CHAN12_EN_S 12 + +/* I2S_TX_TDM_CHAN11_EN : R/W ;bitpos:[11] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel.. + */ + +#define I2S_TX_TDM_CHAN11_EN (BIT(11)) +#define I2S_TX_TDM_CHAN11_EN_M (BIT(11)) +#define I2S_TX_TDM_CHAN11_EN_V 0x1 +#define I2S_TX_TDM_CHAN11_EN_S 11 + +/* I2S_TX_TDM_CHAN10_EN : R/W ;bitpos:[10] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel.. + */ + +#define I2S_TX_TDM_CHAN10_EN (BIT(10)) +#define I2S_TX_TDM_CHAN10_EN_M (BIT(10)) +#define I2S_TX_TDM_CHAN10_EN_V 0x1 +#define I2S_TX_TDM_CHAN10_EN_S 10 + +/* I2S_TX_TDM_CHAN9_EN : R/W ;bitpos:[9] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN9_EN (BIT(9)) +#define I2S_TX_TDM_CHAN9_EN_M (BIT(9)) +#define I2S_TX_TDM_CHAN9_EN_V 0x1 +#define I2S_TX_TDM_CHAN9_EN_S 9 + +/* I2S_TX_TDM_CHAN8_EN : R/W ;bitpos:[8] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN8_EN (BIT(8)) +#define I2S_TX_TDM_CHAN8_EN_M (BIT(8)) +#define I2S_TX_TDM_CHAN8_EN_V 0x1 +#define I2S_TX_TDM_CHAN8_EN_S 8 + +/* I2S_TX_TDM_CHAN7_EN : R/W ;bitpos:[7] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN7_EN (BIT(7)) +#define I2S_TX_TDM_CHAN7_EN_M (BIT(7)) +#define I2S_TX_TDM_CHAN7_EN_V 0x1 +#define I2S_TX_TDM_CHAN7_EN_S 7 + +/* I2S_TX_TDM_CHAN6_EN : R/W ;bitpos:[6] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN6_EN (BIT(6)) +#define I2S_TX_TDM_CHAN6_EN_M (BIT(6)) +#define I2S_TX_TDM_CHAN6_EN_V 0x1 +#define I2S_TX_TDM_CHAN6_EN_S 6 + +/* I2S_TX_TDM_CHAN5_EN : R/W ;bitpos:[5] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN5_EN (BIT(5)) +#define I2S_TX_TDM_CHAN5_EN_M (BIT(5)) +#define I2S_TX_TDM_CHAN5_EN_V 0x1 +#define I2S_TX_TDM_CHAN5_EN_S 5 + +/* I2S_TX_TDM_CHAN4_EN : R/W ;bitpos:[4] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel.. + */ + +#define I2S_TX_TDM_CHAN4_EN (BIT(4)) +#define I2S_TX_TDM_CHAN4_EN_M (BIT(4)) +#define I2S_TX_TDM_CHAN4_EN_V 0x1 +#define I2S_TX_TDM_CHAN4_EN_S 4 + +/* I2S_TX_TDM_CHAN3_EN : R/W ;bitpos:[3] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel.. + */ + +#define I2S_TX_TDM_CHAN3_EN (BIT(3)) +#define I2S_TX_TDM_CHAN3_EN_M (BIT(3)) +#define I2S_TX_TDM_CHAN3_EN_V 0x1 +#define I2S_TX_TDM_CHAN3_EN_S 3 + +/* I2S_TX_TDM_CHAN2_EN : R/W ;bitpos:[2] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel.. + */ + +#define I2S_TX_TDM_CHAN2_EN (BIT(2)) +#define I2S_TX_TDM_CHAN2_EN_M (BIT(2)) +#define I2S_TX_TDM_CHAN2_EN_V 0x1 +#define I2S_TX_TDM_CHAN2_EN_S 2 + +/* I2S_TX_TDM_CHAN1_EN : R/W ;bitpos:[1] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel.. + */ + +#define I2S_TX_TDM_CHAN1_EN (BIT(1)) +#define I2S_TX_TDM_CHAN1_EN_M (BIT(1)) +#define I2S_TX_TDM_CHAN1_EN_V 0x1 +#define I2S_TX_TDM_CHAN1_EN_S 1 + +/* I2S_TX_TDM_CHAN0_EN : R/W ;bitpos:[0] ;default: 1'h1 ; */ + +/* Description: + * 1: Enable the valid data output of I2S TX TDM channel $n. + * 0: Disable, just output 0 in this channel. + */ + +#define I2S_TX_TDM_CHAN0_EN (BIT(0)) +#define I2S_TX_TDM_CHAN0_EN_M (BIT(0)) +#define I2S_TX_TDM_CHAN0_EN_V 0x1 +#define I2S_TX_TDM_CHAN0_EN_S 0 + +#define I2S_RX_TIMING_REG(i) (REG_I2S_BASE(i) + 0x58) + +/* I2S_RX_BCK_IN_DM : R/W ;bitpos:[29:28] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx BCK input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used.. + */ + +#define I2S_RX_BCK_IN_DM 0x00000003 +#define I2S_RX_BCK_IN_DM_M ((I2S_RX_BCK_IN_DM_V)<<(I2S_RX_BCK_IN_DM_S)) +#define I2S_RX_BCK_IN_DM_V 0x3 +#define I2S_RX_BCK_IN_DM_S 28 + +/* I2S_RX_WS_IN_DM : R/W ;bitpos:[25:24] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx WS input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used. + */ + +#define I2S_RX_WS_IN_DM 0x00000003 +#define I2S_RX_WS_IN_DM_M ((I2S_RX_WS_IN_DM_V)<<(I2S_RX_WS_IN_DM_S)) +#define I2S_RX_WS_IN_DM_V 0x3 +#define I2S_RX_WS_IN_DM_S 24 + +/* I2S_RX_BCK_OUT_DM : R/W ;bitpos:[21:20] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx BCK output signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used.. + */ + +#define I2S_RX_BCK_OUT_DM 0x00000003 +#define I2S_RX_BCK_OUT_DM_M ((I2S_RX_BCK_OUT_DM_V)<<(I2S_RX_BCK_OUT_DM_S)) +#define I2S_RX_BCK_OUT_DM_V 0x3 +#define I2S_RX_BCK_OUT_DM_S 20 + +/* I2S_RX_WS_OUT_DM : R/W ;bitpos:[17:16] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx WS output signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used. + */ + +#define I2S_RX_WS_OUT_DM 0x00000003 +#define I2S_RX_WS_OUT_DM_M ((I2S_RX_WS_OUT_DM_V)<<(I2S_RX_WS_OUT_DM_S)) +#define I2S_RX_WS_OUT_DM_V 0x3 +#define I2S_RX_WS_OUT_DM_S 16 + +/* I2S_RX_SD3_IN_DM : R/W ;bitpos:[13:12] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx SD3 input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used. + */ + +#define I2S_RX_SD3_IN_DM 0x00000003 +#define I2S_RX_SD3_IN_DM_M ((I2S_RX_SD3_IN_DM_V)<<(I2S_RX_SD3_IN_DM_S)) +#define I2S_RX_SD3_IN_DM_V 0x3 +#define I2S_RX_SD3_IN_DM_S 12 + +/* I2S_RX_SD2_IN_DM : R/W ;bitpos:[9:8] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx SD2 input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used. + */ + +#define I2S_RX_SD2_IN_DM 0x00000003 +#define I2S_RX_SD2_IN_DM_M ((I2S_RX_SD2_IN_DM_V)<<(I2S_RX_SD2_IN_DM_S)) +#define I2S_RX_SD2_IN_DM_V 0x3 +#define I2S_RX_SD2_IN_DM_S 8 + +/* I2S_RX_SD1_IN_DM : R/W ;bitpos:[5:4] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx SD1 input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used. + */ + +#define I2S_RX_SD1_IN_DM 0x00000003 +#define I2S_RX_SD1_IN_DM_M ((I2S_RX_SD1_IN_DM_V)<<(I2S_RX_SD1_IN_DM_S)) +#define I2S_RX_SD1_IN_DM_V 0x3 +#define I2S_RX_SD1_IN_DM_S 4 + +/* I2S_RX_SD_IN_DM : R/W ;bitpos:[1:0] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S Rx SD input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used. + */ + +#define I2S_RX_SD_IN_DM 0x00000003 +#define I2S_RX_SD_IN_DM_M ((I2S_RX_SD_IN_DM_V)<<(I2S_RX_SD_IN_DM_S)) +#define I2S_RX_SD_IN_DM_V 0x3 +#define I2S_RX_SD_IN_DM_S 0 + +#define I2S_TX_TIMING_REG(i) (REG_I2S_BASE(i) + 0x5C) + +/* I2S_TX_BCK_IN_DM : R/W ;bitpos:[29:28] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S TX BCK input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used.. + */ + +#define I2S_TX_BCK_IN_DM 0x00000003 +#define I2S_TX_BCK_IN_DM_M ((I2S_TX_BCK_IN_DM_V)<<(I2S_TX_BCK_IN_DM_S)) +#define I2S_TX_BCK_IN_DM_V 0x3 +#define I2S_TX_BCK_IN_DM_S 28 + +/* I2S_TX_WS_IN_DM : R/W ;bitpos:[25:24] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S TX WS input signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used.. + */ + +#define I2S_TX_WS_IN_DM 0x00000003 +#define I2S_TX_WS_IN_DM_M ((I2S_TX_WS_IN_DM_V)<<(I2S_TX_WS_IN_DM_S)) +#define I2S_TX_WS_IN_DM_V 0x3 +#define I2S_TX_WS_IN_DM_S 24 + +/* I2S_TX_BCK_OUT_DM : R/W ;bitpos:[21:20] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S TX BCK output signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used. + */ + +#define I2S_TX_BCK_OUT_DM 0x00000003 +#define I2S_TX_BCK_OUT_DM_M ((I2S_TX_BCK_OUT_DM_V)<<(I2S_TX_BCK_OUT_DM_S)) +#define I2S_TX_BCK_OUT_DM_V 0x3 +#define I2S_TX_BCK_OUT_DM_S 20 + +/* I2S_TX_WS_OUT_DM : R/W ;bitpos:[17:16] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S TX WS output signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used.. + */ + +#define I2S_TX_WS_OUT_DM 0x00000003 +#define I2S_TX_WS_OUT_DM_M ((I2S_TX_WS_OUT_DM_V)<<(I2S_TX_WS_OUT_DM_S)) +#define I2S_TX_WS_OUT_DM_V 0x3 +#define I2S_TX_WS_OUT_DM_S 16 + +/* I2S_TX_SD1_OUT_DM : R/W ;bitpos:[5:4] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S TX SD1 output signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used.. + */ + +#define I2S_TX_SD1_OUT_DM 0x00000003 +#define I2S_TX_SD1_OUT_DM_M ((I2S_TX_SD1_OUT_DM_V)<<(I2S_TX_SD1_OUT_DM_S)) +#define I2S_TX_SD1_OUT_DM_V 0x3 +#define I2S_TX_SD1_OUT_DM_S 4 + +/* I2S_TX_SD_OUT_DM : R/W ;bitpos:[1:0] ;default: 2'h0 ; */ + +/* Description: + * The delay mode of I2S TX SD output signal. + * 0: bypass. + * 1: delay by pos edge. + * 2: delay by neg edge. + * 3: not used.. + */ + +#define I2S_TX_SD_OUT_DM 0x00000003 +#define I2S_TX_SD_OUT_DM_M ((I2S_TX_SD_OUT_DM_V)<<(I2S_TX_SD_OUT_DM_S)) +#define I2S_TX_SD_OUT_DM_V 0x3 +#define I2S_TX_SD_OUT_DM_S 0 + +#define I2S_LC_HUNG_CONF_REG(i) (REG_I2S_BASE(i) + 0x60) + +/* I2S_LC_FIFO_TIMEOUT_ENA : R/W ;bitpos:[11] ;default: 1'b1 ; */ + +/* Description: The enable bit for FIFO timeout. */ + +#define I2S_LC_FIFO_TIMEOUT_ENA (BIT(11)) +#define I2S_LC_FIFO_TIMEOUT_ENA_M (BIT(11)) +#define I2S_LC_FIFO_TIMEOUT_ENA_V 0x1 +#define I2S_LC_FIFO_TIMEOUT_ENA_S 11 + +/* I2S_LC_FIFO_TIMEOUT_SHIFT : R/W ;bitpos:[10:8] ;default: 3'b0 ; */ + +/* Description: + * The bits are used to scale tick counter threshold. The tick counter + * is reset when counter value >= 88000/2^i2s_lc_fifo_timeout_shift. + */ + +#define I2S_LC_FIFO_TIMEOUT_SHIFT 0x00000007 +#define I2S_LC_FIFO_TIMEOUT_SHIFT_M ((I2S_LC_FIFO_TIMEOUT_SHIFT_V)<<(I2S_LC_FIFO_TIMEOUT_SHIFT_S)) +#define I2S_LC_FIFO_TIMEOUT_SHIFT_V 0x7 +#define I2S_LC_FIFO_TIMEOUT_SHIFT_S 8 + +/* I2S_LC_FIFO_TIMEOUT : R/W ;bitpos:[7:0] ;default: 8'h10 ; */ + +/* Description: + * The i2s_tx_hung_int interrupt or the i2s_rx_hung_int interrupt will be + * triggered when fifo hung counter is equal to this value. + */ + +#define I2S_LC_FIFO_TIMEOUT 0x000000FF +#define I2S_LC_FIFO_TIMEOUT_M ((I2S_LC_FIFO_TIMEOUT_V)<<(I2S_LC_FIFO_TIMEOUT_S)) +#define I2S_LC_FIFO_TIMEOUT_V 0xFF +#define I2S_LC_FIFO_TIMEOUT_S 0 + +#define I2S_RXEOF_NUM_REG(i) (REG_I2S_BASE(i) + 0x64) + +/* I2S_RX_EOF_NUM : R/W ;bitpos:[11:0] ;default: 12'h40 ; */ + +/* Description: + * The receive data bit length is + * (I2S_RX_BITS_MOD[4:0] + 1) * (REG_RX_EOF_NUM[11:0] + 1). It will trigger + * in_suc_eof interrupt in the configured DMA RX channel. + */ + +#define I2S_RX_EOF_NUM 0x00000FFF +#define I2S_RX_EOF_NUM_M ((I2S_RX_EOF_NUM_V)<<(I2S_RX_EOF_NUM_S)) +#define I2S_RX_EOF_NUM_V 0xFFF +#define I2S_RX_EOF_NUM_S 0 + +#define I2S_CONF_SIGLE_DATA_REG(i) (REG_I2S_BASE(i) + 0x68) + +/* I2S_SINGLE_DATA : R/W ;bitpos:[31:0] ;default: 32'd0 ; */ + +/* Description: The configured constant channel data to be sent out. */ + +#define I2S_SINGLE_DATA 0xFFFFFFFF +#define I2S_SINGLE_DATA_M ((I2S_SINGLE_DATA_V)<<(I2S_SINGLE_DATA_S)) +#define I2S_SINGLE_DATA_V 0xFFFFFFFF +#define I2S_SINGLE_DATA_S 0 + +#define I2S_STATE_REG(i) (REG_I2S_BASE(i) + 0x6C) + +/* I2S_TX_IDLE : RO ;bitpos:[0] ;default: 1'b1 ; */ + +/* Description: + * 1: i2s_tx is idle state. + * 0: i2s_tx is working.. + */ + +#define I2S_TX_IDLE (BIT(0)) +#define I2S_TX_IDLE_M (BIT(0)) +#define I2S_TX_IDLE_V 0x1 +#define I2S_TX_IDLE_S 0 + +#define I2S_DATE_REG(i) (REG_I2S_BASE(i) + 0x80) + +/* I2S_DATE : R/W ;bitpos:[27:0] ;default: 28'h2009070 ; */ + +/* Description: I2S version control register. */ + +#define I2S_DATE 0x0FFFFFFF +#define I2S_DATE_M ((I2S_DATE_V)<<(I2S_DATE_S)) +#define I2S_DATE_V 0xFFFFFFF +#define I2S_DATE_S 0 + +#endif /* __ARCH_XTENSA_SRC_ESP32S3_HARDWARE_ESP32S3_I2S_H */