This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 18c715ba9283dda403aeeb73db2b299e081e3bfa
Author: Tiago Medicci Serrano <tiago.medi...@espressif.com>
AuthorDate: Wed Sep 28 15:01:53 2022 -0300

    xtensa/esp32: add initial support for I2S
    
    Add initial support for the I2S peripheral on ESP32.
    Add I2S character driver and generic I2S audio driver.
    Include i2schar defconfig for ESP32-DevKitC board.
---
 arch/xtensa/src/esp32/Kconfig                      |  291 ++-
 arch/xtensa/src/esp32/Make.defs                    |    4 +
 arch/xtensa/src/esp32/esp32_dma.c                  |   79 +
 arch/xtensa/src/esp32/esp32_dma.h                  |   26 +
 arch/xtensa/src/esp32/esp32_i2s.c                  | 1647 ++++++++++++++++
 arch/xtensa/src/esp32/{esp32_dma.h => esp32_i2s.h} |   60 +-
 arch/xtensa/src/esp32/hardware/esp32_i2s.h         | 2037 +++++++++++++++++++-
 boards/xtensa/esp32/common/src/Make.defs           |    4 +
 .../xtensa/esp32/common/src/esp32_board_i2sdev.c   |  109 ++
 .../esp32/esp32-devkitc/configs/i2schar/defconfig  |   62 +
 .../xtensa/esp32/esp32-devkitc/src/esp32-devkitc.h |   22 +
 .../xtensa/esp32/esp32-devkitc/src/esp32_bringup.c |   34 +
 12 files changed, 4308 insertions(+), 67 deletions(-)

diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig
index 426f188b8c..dd34818a57 100644
--- a/arch/xtensa/src/esp32/Kconfig
+++ b/arch/xtensa/src/esp32/Kconfig
@@ -276,20 +276,6 @@ config ESP32_TWAI
        default n
        select CAN
 
-config ESP32_I2S0
-       bool "I2S 0"
-       default n
-       depends on EXPERIMENTAL
-       ---help---
-               No yet implemented
-
-config ESP32_I2S1
-       bool "I2S 2"
-       default n
-       depends on EXPERIMENTAL
-       ---help---
-               No yet implemented
-
 config ESP32_LEDC
        bool "LEDC (PWM)"
        default n
@@ -333,6 +319,283 @@ config ESP32_SDMMC
        ---help---
                No yet implemented
 
+config ESP32_I2S
+       bool "I2S"
+       select I2S
+       ---help---
+               See the Board Selection menu to configure the pins used by I2S.
+
+if ESP32_I2S
+
+config ESP32_I2S0
+       bool "I2S 0"
+       default n
+       select ARCH_DMA
+       select ESP32_GPIO_IRQ
+
+if ESP32_I2S0
+
+config ESP32_I2S0_RX
+       bool "Enable I2S receiver"
+       default y
+       ---help---
+               Enable I2S receive logic
+
+config ESP32_I2S0_TX
+       bool "Enable I2S transmitter"
+       default y
+       ---help---
+               Enable I2S transmit logic
+
+choice
+       prompt "I2S0 role"
+       default ESP32_I2S0_ROLE_MASTER
+       ---help---
+               Selects the operation role of the I2S0.
+
+config ESP32_I2S0_ROLE_MASTER
+       bool "Master"
+
+config ESP32_I2S0_ROLE_SLAVE
+       bool "Slave"
+
+endchoice
+
+choice
+       prompt "Bit width"
+       ---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 ESP32_I2S0_DATA_BIT_WIDTH_8BIT
+       bool "8 bits"
+
+config ESP32_I2S0_DATA_BIT_WIDTH_16BIT
+       bool "16 bits"
+
+config ESP32_I2S0_DATA_BIT_WIDTH_24BIT
+       bool "24 bits"
+
+config ESP32_I2S0_DATA_BIT_WIDTH_32BIT
+       bool "32 bits"
+
+endchoice
+
+config ESP32_I2S0_DATA_BIT_WIDTH
+       int
+       default 8 if ESP32_I2S0_DATA_BIT_WIDTH_8BIT
+       default 16 if ESP32_I2S0_DATA_BIT_WIDTH_16BIT
+       default 24 if ESP32_I2S0_DATA_BIT_WIDTH_24BIT
+       default 32 if ESP32_I2S0_DATA_BIT_WIDTH_32BIT
+
+config ESP32_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 ESP32_I2S0_BCLKPIN
+       int "I2S0 BCLK pin"
+       default 4
+       range 0 33 if ESP32_I2S0_ROLE_MASTER
+       range 0 39 if ESP32_I2S0_ROLE_SLAVE
+
+config ESP32_I2S0_WSPIN
+       int "I2S0 WS pin"
+       default 5
+       range 0 33 if ESP32_I2S0_ROLE_MASTER
+       range 0 39 if ESP32_I2S0_ROLE_SLAVE
+
+config ESP32_I2S0_DINPIN
+       int "I2S0 DOUT pin"
+       depends on ESP32_I2S0_RX
+       default 12
+       range 0 39
+
+config ESP32_I2S0_DOUTPIN
+       int "I2S0 DOUT pin"
+       depends on ESP32_I2S0_TX
+       default 18
+       range 0 33
+
+config ESP32_I2S0_MCLK
+       bool "Enable I2S Master Clock"
+       depends on ESP32_I2S0_ROLE_MASTER
+       default n
+       ---help---
+               Enable I2S master clock
+
+choice
+       prompt "I2S0 MCLK pin"
+       depends on ESP32_I2S0_MCLK
+       default ESP32_I2S0_MCLKPIN_GPIO0
+       ---help---
+               Selects the pin to output master clock.
+
+config ESP32_I2S0_MCLKPIN_GPIO0
+       bool "GPIO0"
+
+config ESP32_I2S0_MCLKPIN_GPIO1
+       bool "GPIO1 (U0TXD)"
+
+config ESP32_I2S0_MCLKPIN_GPIO3
+       bool "GPIO3 [U0RXD]"
+
+endchoice
+
+config ESP32_I2S0_MCLKPIN
+       int
+       default 0
+       default 0 if ESP32_I2S0_MCLKPIN_GPIO0
+       default 1 if ESP32_I2S0_MCLKPIN_GPIO1
+       default 3 if ESP32_I2S0_MCLKPIN_GPIO3
+
+endif #ESP32_I2S0
+
+config ESP32_I2S1
+       bool "I2S 1"
+       default n
+       select ARCH_DMA
+       select ESP32_GPIO_IRQ
+
+if ESP32_I2S1
+
+config ESP32_I2S1_RX
+       bool "Enable I2S receiver"
+       default y
+       ---help---
+               Enable I2S receive logic
+
+config ESP32_I2S1_TX
+       bool "Enable I2S transmitter"
+       default y
+       ---help---
+               Enable I2S transmit logic
+
+choice
+       prompt "I2S1 role"
+       default ESP32_I2S1_ROLE_MASTER
+       ---help---
+               Selects the operation role of the I2S1.
+
+config ESP32_I2S1_ROLE_MASTER
+       bool "Master"
+
+config ESP32_I2S1_ROLE_SLAVE
+       bool "Slave"
+
+endchoice
+
+choice
+       prompt "Bit width"
+       ---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 ESP32_I2S1_DATA_BIT_WIDTH_8BIT
+       bool "8 bits"
+
+config ESP32_I2S1_DATA_BIT_WIDTH_16BIT
+       bool "16 bits"
+
+config ESP32_I2S1_DATA_BIT_WIDTH_24BIT
+       bool "24 bits"
+
+config ESP32_I2S1_DATA_BIT_WIDTH_32BIT
+       bool "32 bits"
+
+endchoice
+
+config ESP32_I2S1_DATA_BIT_WIDTH
+       int
+       default 16
+       default 8 if ESP32_I2S1_DATA_BIT_WIDTH_8BIT
+       default 16 if ESP32_I2S1_DATA_BIT_WIDTH_16BIT
+       default 24 if ESP32_I2S1_DATA_BIT_WIDTH_24BIT
+       default 32 if ESP32_I2S1_DATA_BIT_WIDTH_32BIT
+
+config ESP32_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 ESP32_I2S1_BCLKPIN
+       int "I2S1 BCLK pin"
+       default 19
+       range 0 33 if ESP32_I2S1_ROLE_MASTER
+       range 0 39 if ESP32_I2S1_ROLE_SLAVE
+
+config ESP32_I2S1_WSPIN
+       int "I2S1 WS pin"
+       default 18
+       range 0 33 if ESP32_I2S1_ROLE_MASTER
+       range 0 39 if ESP32_I2S1_ROLE_SLAVE
+
+config ESP32_I2S1_DOUTPIN
+       int "I2S1 DOUT pin"
+       depends on ESP32_I2S1_RX
+       default 17
+       range 0 39
+
+config ESP32_I2S1_DOUTPIN
+       int "I2S1 DOUT pin"
+       depends on ESP32_I2S1_TX
+       default 16
+       range 0 33
+
+config ESP32_I2S1_MCLK
+       bool "Enable I2S Master Clock"
+       depends on ESP32_I2S1_ROLE_MASTER
+       default n
+       ---help---
+               Enable I2S master clock
+
+choice
+       prompt "I2S1 MCLK pin"
+       depends on ESP32_I2S1_MCLK
+       default ESP32_I2S1_MCLKPIN_GPIO0
+       ---help---
+               Selects the pin to output master clock.
+
+config ESP32_I2S1_MCLKPIN_GPIO0
+       bool "GPIO0"
+
+config ESP32_I2S1_MCLKPIN_GPIO1
+       bool "GPIO1 (U0TXD)"
+
+config ESP32_I2S1_MCLKPIN_GPIO3
+       bool "GPIO3 [U0RXD]"
+
+endchoice
+
+config ESP32_I2S1_MCLKPIN
+       int
+       default 0
+       default 0 if ESP32_I2S1_MCLKPIN_GPIO0
+       default 1 if ESP32_I2S1_MCLKPIN_GPIO1
+       default 3 if ESP32_I2S1_MCLKPIN_GPIO3
+
+endif #ESP32_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 #ESP32_I2S
+
+
 config ESP32_SPI
        bool
        default n
diff --git a/arch/xtensa/src/esp32/Make.defs b/arch/xtensa/src/esp32/Make.defs
index dfb47c46ec..14c5dbc7e0 100644
--- a/arch/xtensa/src/esp32/Make.defs
+++ b/arch/xtensa/src/esp32/Make.defs
@@ -70,6 +70,10 @@ ifeq ($(CONFIG_ESP32_I2C),y)
 CHIP_CSRCS += esp32_i2c.c
 endif
 
+ifeq ($(CONFIG_ESP32_I2S),y)
+CHIP_CSRCS += esp32_i2s.c
+endif
+
 ifeq ($(CONFIG_ESP32_TWAI),y)
 CHIP_CSRCS += esp32_twai.c
 endif
diff --git a/arch/xtensa/src/esp32/esp32_dma.c 
b/arch/xtensa/src/esp32/esp32_dma.c
index d398f5bf4e..532ce0bd4b 100644
--- a/arch/xtensa/src/esp32/esp32_dma.c
+++ b/arch/xtensa/src/esp32/esp32_dma.c
@@ -105,3 +105,82 @@ uint32_t esp32_dma_init(struct esp32_dmadesc_s *dmadesc, 
uint32_t num,
 
   return len - bytes;
 }
+
+/****************************************************************************
+ * Name: esp32_dma_init_with_padding
+ *
+ * Description:
+ *   Initialize DMA outlink descriptors and bind the target buffer to
+ *   these DMA descriptors. If len is not word-aligned, add a new descriptor
+ *   containing a 4-byte variable to make the outlink data world-aligned.
+ *
+ * Input Parameters:
+ *   dmadesc - DMA descriptions pointer
+ *   num     - DMA descriptions number
+ *   pbuf    - RX/TX buffer pointer
+ *   len     - RX/TX buffer length
+ *   stuff   - Value to be padded with the buffer
+ *
+ * Returned Value:
+ *   Binded pbuf data bytes
+ *
+ ****************************************************************************/
+
+uint32_t esp32_dma_init_with_padding(struct esp32_dmadesc_s *dmadesc,
+                                     uint32_t num,
+                                     uint8_t *pbuf,
+                                     uint32_t len,
+                                     uint32_t *stuff)
+{
+  int i;
+  uint32_t bytes = len;
+  uint8_t *pdata = pbuf;
+  uint32_t data_len = 0;
+  uint32_t buf_len = 0;
+
+  DEBUGASSERT(dmadesc != NULL);
+  DEBUGASSERT(pbuf != NULL);
+  DEBUGASSERT(len > 0);
+
+  for (i = 0; i < num - 1; i++)
+    {
+      data_len = MIN(bytes, ESP32_DMA_DATALEN_MAX);
+
+      /* Buffer length must be rounded to next 32-bit boundary. */
+
+      buf_len = ALIGN_UP(data_len, sizeof(uintptr_t));
+
+      dmadesc[i].ctrl = (data_len << DMA_CTRL_DATALEN_S) |
+                        (buf_len << DMA_CTRL_BUFLEN_S) |
+                        DMA_CTRL_OWN;
+      dmadesc[i].pbuf = pdata;
+      dmadesc[i].next = &dmadesc[i + 1];
+
+      bytes -= data_len;
+      if (bytes == 0)
+        {
+          break;
+        }
+
+      pdata += data_len;
+    }
+
+  /* Check if the data_len of the last descriptor is different from buf_len.
+   * If so, it's necessary to add the padding bytes to a new descriptor on
+   * outlink.
+   */
+
+  if (data_len != buf_len)
+    {
+      i++;
+      dmadesc[i].ctrl = ((buf_len - data_len) << DMA_CTRL_DATALEN_S) |
+                        (4 << DMA_CTRL_BUFLEN_S) |
+                        DMA_CTRL_OWN;
+      dmadesc[i].pbuf = (uint8_t *)stuff;
+    }
+
+  dmadesc[i].ctrl |= DMA_CTRL_EOF;
+  dmadesc[i].next  = NULL;
+
+  return len - bytes;
+}
diff --git a/arch/xtensa/src/esp32/esp32_dma.h 
b/arch/xtensa/src/esp32/esp32_dma.h
index 1768da02b3..dfebd3e92b 100644
--- a/arch/xtensa/src/esp32/esp32_dma.h
+++ b/arch/xtensa/src/esp32/esp32_dma.h
@@ -89,6 +89,32 @@ struct esp32_dmadesc_s
 uint32_t esp32_dma_init(struct esp32_dmadesc_s *dmadesc, uint32_t num,
                         uint8_t *pbuf, uint32_t len);
 
+/****************************************************************************
+ * Name: esp32_dma_init_with_padding
+ *
+ * Description:
+ *   Initialize DMA outlink descriptors and bind the target buffer to
+ *   these DMA descriptors. If len is not word-aligned, add a new descriptor
+ *   containing a 4-byte variable to make the outlink data world-aligned.
+ *
+ * Input Parameters:
+ *   dmadesc - DMA descriptions pointer
+ *   num     - DMA descriptions number
+ *   pbuf    - RX/TX buffer pointer
+ *   len     - RX/TX buffer length
+ *   stuff   - Value to be padded with the buffer
+ *
+ * Returned Value:
+ *   Binded pbuf data bytes
+ *
+ ****************************************************************************/
+
+uint32_t esp32_dma_init_with_padding(struct esp32_dmadesc_s *dmadesc,
+                                     uint32_t num,
+                                     uint8_t *pbuf,
+                                     uint32_t len,
+                                     uint32_t *stuff);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/arch/xtensa/src/esp32/esp32_i2s.c 
b/arch/xtensa/src/esp32/esp32_i2s.c
new file mode 100644
index 0000000000..34507d565b
--- /dev/null
+++ b/arch/xtensa/src/esp32/esp32_i2s.c
@@ -0,0 +1,1647 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32/esp32_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 <nuttx/config.h>
+
+#ifdef CONFIG_ESP32_I2S
+
+#include <debug.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/mqueue.h>
+#include <nuttx/mm/circbuf.h>
+#include <nuttx/audio/audio.h>
+#include <nuttx/audio/i2s.h>
+
+#include <arch/board/board.h>
+
+#include "esp32_i2s.h"
+#include "esp32_gpio.h"
+#include "esp32_irq.h"
+#include "esp32_dma.h"
+
+#include "xtensa.h"
+#include "hardware/esp32_gpio_sigmap.h"
+#include "hardware/esp32_dport.h"
+#include "hardware/esp32_i2s.h"
+#include "hardware/esp32_soc.h"
+#include "hardware/esp32_iomux.h"
+#include "hardware/esp32_pinmap.h"
+#include "hardware/esp32_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_ESP32_I2S0_TX
+  #define I2S0_TX_ENABLED 1
+  #define I2S_HAVE_TX 1
+#else
+  #define I2S0_TX_ENABLED 0
+#endif
+
+#ifdef CONFIG_ESP32_I2S0_RX
+  #define I2S0_RX_ENABLED 1
+#else
+  #define I2S0_RX_ENABLED 0
+#endif
+
+#ifdef CONFIG_ESP32_I2S1_TX
+  #define I2S1_TX_ENABLED 1
+  #define I2S_HAVE_TX 1
+#else
+  #define I2S1_TX_ENABLED 0
+#endif
+
+#ifdef CONFIG_ESP32_I2S1_RX
+  #define I2S1_RX_ENABLED 1
+#else
+  #define I2S1_RX_ENABLED 0
+#endif
+
+/* Debug ********************************************************************/
+
+#ifdef CONFIG_DEBUG_I2S_INFO
+#  define CONFIG_ESP32_I2S_DUMPBUFFERS
+#else
+#  undef CONFIG_ESP32_I2S_DUMPBUFFERS
+#endif
+
+#ifndef CONFIG_ESP32_I2S_MAXINFLIGHT
+#  define CONFIG_ESP32_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 Device hardware configuration */
+
+struct esp32_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 is_apll;               /* Select APLL as the source clock */
+  uint32_t mclk_multiple;     /* The multiple of mclk to the sample rate */
+
+  bool tx_en;                 /* Is TX enabled? */
+  bool rx_en;                 /* Is RX enabled? */
+  int8_t mclk_pin;            /* MCLK pin, output */
+
+  /* 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 */
+
+  uint8_t periph;             /* peripher ID */
+  uint8_t irq;                /* Interrupt ID */
+
+  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 */
+
+  bool bit_shift;             /* Set to enable bit shift in Philips mode */
+  bool mono_en;               /* Set to enable mono mode on slot */
+
+  /* WS signal width (the number of bclk ticks that ws signal is high) */
+
+  uint32_t ws_width;
+
+  /* WS signal polarity, set true to enable high lever first */
+
+  bool ws_pol;
+};
+
+struct esp32_buffer_s
+{
+  struct esp32_buffer_s *flink; /* Supports a singly linked list */
+
+  /* The associated DMA outlink */
+
+  struct esp32_dmadesc_s dma_outlink[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 */
+  int result;                   /* The result of the transfer */
+};
+
+/* This structure describes the state of one receiver or transmitter
+ * transport.
+ */
+
+struct esp32_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 */
+};
+
+/* The state of the one I2S peripheral */
+
+struct esp32_i2s_s
+{
+  struct i2s_dev_s  dev;        /* Externally visible I2S interface */
+  sem_t             exclsem;    /* Assures mutually exclusive access */
+  uint32_t          rate;       /* I2S actual configured sample-rate */
+  uint32_t          data_width; /* I2S actual configured data_width */
+  int               cpuint;     /* I2S interrupt ID */
+  uint8_t           cpu;        /* CPU ID */
+  spinlock_t        lock;       /* Device specific lock. */
+
+  /* Port configuration */
+
+  const struct esp32_i2s_config_s *config;
+
+#ifdef I2S_HAVE_TX
+  struct esp32_transport_s tx;  /* TX transport state */
+
+  /* Stuff var to fill DMA buffer if not word-aligned */
+
+  uint32_t stuff;
+#endif /* I2S_HAVE_TX */
+
+  /* Pre-allocated pool of buffer containers */
+
+  sem_t bufsem;                       /* Buffer wait semaphore */
+  struct esp32_buffer_s *bf_freelist; /* A list a free buffer containers */
+  struct esp32_buffer_s containers[CONFIG_ESP32_I2S_MAXINFLIGHT];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Register helpers */
+
+#ifdef CONFIG_ESP32_I2S_DUMPBUFFERS
+#  define       i2s_dump_buffer(m,b,s) lib_dumpbuffer(m,b,s)
+#else
+#  define       i2s_dump_buffer(m,b,s)
+#endif
+
+/* Semaphore helpers */
+
+static int      i2s_exclsem_take(struct esp32_i2s_s *priv);
+#define         i2s_exclsem_give(priv) nxsem_post(&priv->exclsem)
+
+static int      i2s_bufsem_take(struct esp32_i2s_s *priv);
+#define         i2s_bufsem_give(priv) nxsem_post(&priv->bufsem)
+
+/* Buffer container helpers */
+
+static struct esp32_buffer_s *
+                i2s_buf_allocate(struct esp32_i2s_s *priv);
+static void     i2s_buf_free(struct esp32_i2s_s *priv,
+                  struct esp32_buffer_s *bfcontainer);
+static int      i2s_buf_initialize(struct esp32_i2s_s *priv);
+
+/* DMA support */
+
+#ifdef I2S_HAVE_TX
+static int      i2s_txdma_setup(struct esp32_i2s_s *priv,
+                                struct esp32_buffer_s *bfcontainer);
+static void     i2s_tx_worker(void *arg);
+static void     i2s_tx_schedule(struct esp32_i2s_s *priv,
+                                struct esp32_dmadesc_s *outlink);
+#endif /* I2S_HAVE_TX */
+
+/* I2S methods (and close friends) */
+
+static uint32_t esp32_i2s_txsamplerate(struct i2s_dev_s *dev,
+                                        uint32_t rate);
+static uint32_t esp32_i2s_txdatawidth(struct i2s_dev_s *dev, int bits);
+static int      esp32_i2s_send(struct i2s_dev_s *dev,
+                                struct ap_buffer_s *apb,
+                                i2s_callback_t callback, void *arg,
+                                uint32_t timeout);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct i2s_ops_s g_i2sops =
+{
+  .i2s_txsamplerate = esp32_i2s_txsamplerate,
+  .i2s_txdatawidth  = esp32_i2s_txdatawidth,
+  .i2s_send         = esp32_i2s_send,
+};
+
+#ifdef CONFIG_ESP32_I2S0
+static const struct esp32_i2s_config_s esp32_i2s0_config =
+{
+  .port             = 0,
+#ifdef CONFIG_ESP32_I2S0_ROLE_MASTER
+  .role             = I2S_ROLE_MASTER,
+#else
+  .role             = I2S_ROLE_SLAVE,
+#endif /* CONFIG_ESP32_I2S0_ROLE_MASTER */
+  .data_width       = CONFIG_ESP32_I2S0_DATA_BIT_WIDTH,
+  .rate             = CONFIG_ESP32_I2S0_SAMPLE_RATE,
+  .total_slot       = 2,
+  .mclk_multiple    = I2S_MCLK_MULTIPLE_384,
+  .tx_en            = I2S0_TX_ENABLED,
+  .rx_en            = I2S0_RX_ENABLED,
+#ifdef CONFIG_ESP32_I2S0_MCLK
+  .mclk_pin         = CONFIG_ESP32_I2S0_MCLKPIN,
+#else
+  .mclk_pin         = I2S_GPIO_UNUSED,
+#endif /* CONFIG_ESP32_I2S0_MCLK */
+  .bclk_pin         = CONFIG_ESP32_I2S0_BCLKPIN,
+  .ws_pin           = CONFIG_ESP32_I2S0_WSPIN,
+#ifdef CONFIG_ESP32_I2S0_DOUTPIN
+  .dout_pin         = CONFIG_ESP32_I2S0_DOUTPIN,
+#else
+  .dout_pin         = I2S_GPIO_UNUSED,
+#endif /* CONFIG_ESP32_I2S0_DOUTPIN */
+#ifdef CONFIG_ESP32_I2S0_DINPIN
+  .din_pin          = CONFIG_ESP32_I2S0_DINPIN,
+#else
+  .din_pin          = I2S_GPIO_UNUSED,
+#endif /* CONFIG_ESP32_I2S0_DINPIN */
+  .periph           = ESP32_PERIPH_I2S0,
+  .irq              = ESP32_IRQ_I2S0,
+  .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_DATA_IN15_IDX,
+  .dout_outsig      = I2S0O_DATA_OUT23_IDX,
+  .bit_shift        = true,
+  .mono_en          = false,
+  .ws_width         = CONFIG_ESP32_I2S0_DATA_BIT_WIDTH,
+};
+
+static struct esp32_i2s_s esp32_i2s0_priv =
+{
+  .dev =
+        {
+          .ops = &g_i2sops
+        },
+  .config = &esp32_i2s0_config
+};
+#endif /* CONFIG_ESP32_I2S0 */
+
+#ifdef CONFIG_ESP32_I2S1
+static const struct esp32_i2s_config_s esp32_i2s1_config =
+{
+  .port             = 1,
+#ifdef CONFIG_ESP32_I2S1_ROLE_MASTER
+  .role             = I2S_ROLE_MASTER,
+#else
+  .role             = I2S_ROLE_SLAVE,
+#endif /* CONFIG_ESP32_I2S1_ROLE_MASTER */
+  .data_width       = CONFIG_ESP32_I2S1_DATA_BIT_WIDTH,
+  .rate             = CONFIG_ESP32_I2S1_SAMPLE_RATE,
+  .total_slot       = 2,
+  .mclk_multiple    = I2S_MCLK_MULTIPLE_384,
+  .tx_en            = I2S1_TX_ENABLED,
+  .rx_en            = I2S1_RX_ENABLED,
+#ifdef CONFIG_ESP32_I2S1_MCLK
+  .mclk_pin         = CONFIG_ESP32_I2S1_MCLKPIN,
+#else
+  .mclk_pin         = I2S_GPIO_UNUSED,
+#endif /* CONFIG_ESP32_I2S1_MCLK */
+  .bclk_pin         = CONFIG_ESP32_I2S1_BCLKPIN,
+  .ws_pin           = CONFIG_ESP32_I2S1_WSPIN,
+#ifdef CONFIG_ESP32_I2S1_DOUTPIN
+  .dout_pin         = CONFIG_ESP32_I2S1_DOUTPIN,
+#else
+  .dout_pin         = I2S_GPIO_UNUSED,
+#endif /* CONFIG_ESP32_I2S1_DOUTPIN */
+#ifdef CONFIG_ESP32_I2S1_DINPIN
+  .din_pin          = CONFIG_ESP32_I2S1_DINPIN,
+#else
+  .din_pin         = I2S_GPIO_UNUSED,
+#endif /* CONFIG_ESP32_I2S1_DINPIN */
+  .periph           = ESP32_PERIPH_I2S1,
+  .irq              = ESP32_IRQ_I2S1,
+  .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_DATA_IN15_IDX,
+  .dout_outsig      = I2S1O_DATA_OUT23_IDX,
+  .bit_shift        = true,
+  .mono_en          = false,
+  .ws_width         = CONFIG_ESP32_I2S1_DATA_BIT_WIDTH,
+};
+
+static struct esp32_i2s_s esp32_i2s1_priv =
+{
+  .dev =
+        {
+          .ops = &g_i2sops
+        },
+  .config = &esp32_i2s1_config
+};
+#endif /* CONFIG_ESP32_I2S1 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2s_exclsem_take
+ *
+ * Description:
+ *   Take the exclusive access semaphore handling any exceptional conditions
+ *
+ * Input Parameters:
+ *   priv - A reference to the i2s peripheral state
+ *
+ * Returned Value:
+ *   Normally OK, but may return -ECANCELED in the rare event that the task
+ *   has been canceled.
+ *
+ ****************************************************************************/
+
+static int i2s_exclsem_take(struct esp32_i2s_s *priv)
+{
+  return nxsem_wait_uninterruptible(&priv->exclsem);
+}
+
+/****************************************************************************
+ * Name: i2s_bufsem_take
+ *
+ * Description:
+ *   Take the buffer semaphore handling any exceptional conditions
+ *
+ * Input Parameters:
+ *   priv - A reference to the i2s peripheral state
+ *
+ * Returned Value:
+ *   Normally OK, but may return -ECANCELED in the rare event that the task
+ *   has been canceled.
+ *
+ ****************************************************************************/
+
+static int i2s_bufsem_take(struct esp32_i2s_s *priv)
+{
+  return nxsem_wait_uninterruptible(&priv->bufsem);
+}
+
+/****************************************************************************
+ * Name: i2s_buf_allocate
+ *
+ * Description:
+ *   Allocate a buffer container by removing the one at the head of the
+ *   free list
+ *
+ * Input Parameters:
+ *   priv - I2S state instance
+ *
+ * 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 esp32_buffer_s *i2s_buf_allocate(struct esp32_i2s_s *priv)
+{
+  struct esp32_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 = i2s_bufsem_take(priv);
+  if (ret < 0)
+    {
+      return NULL;
+    }
+
+  /* Get the buffer from the head of the free list */
+
+  flags = spin_lock_irqsave(&priv->lock);
+  bfcontainer = priv->bf_freelist;
+  DEBUGASSERT(bfcontainer);
+
+  /* Unlink the buffer from the freelist */
+
+  priv->bf_freelist = bfcontainer->flink;
+  spin_unlock_irqrestore(&priv->lock, flags);
+  return bfcontainer;
+}
+
+/****************************************************************************
+ * Name: i2s_buf_free
+ *
+ * Description:
+ *   Free buffer container by adding it to the head of the free list
+ *
+ * Input Parameters:
+ *   priv - I2S state instance
+ *   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 esp32_i2s_s *priv,
+                         struct esp32_buffer_s *bfcontainer)
+{
+  irqstate_t flags;
+
+  /* Put the buffer container back on the free list (circbuf) */
+
+  flags = spin_lock_irqsave(&priv->lock);
+
+  bfcontainer->apb = NULL;
+  bfcontainer->flink  = priv->bf_freelist;
+  priv->bf_freelist = bfcontainer;
+
+  spin_unlock_irqrestore(&priv->lock, flags);
+
+  /* Wake up any threads waiting for a buffer container */
+
+  i2s_bufsem_give(priv);
+}
+
+/****************************************************************************
+ * 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 - I2S state instance
+ *
+ * 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 esp32_i2s_s *priv)
+{
+  int ret;
+
+  priv->bf_freelist = NULL;
+  ret = nxsem_init(&priv->bufsem, 0, 0);
+
+  if (ret < 0)
+    {
+      i2serr("ERROR: nxsem_init failed: %d\n", ret);
+      return ret;
+    }
+
+  for (int i = 0; i < CONFIG_ESP32_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 interruption level.
+ *
+ * Input Parameters:
+ *   priv - I2S state instance
+ *
+ * Returned Value:
+ *   OK on success; a negated errno value on failure
+ *
+ * Assumptions:
+ *   Interrupts are disabled
+ *
+ ****************************************************************************/
+
+#ifdef I2S_HAVE_TX
+static int i2s_txdma_start(struct esp32_i2s_s *priv)
+{
+  struct esp32_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;
+    }
+
+  bfcontainer = (struct esp32_buffer_s *)sq_remfirst(&priv->tx.pend);
+
+  /* If there isn't already an active transmission in progress,
+   * then start it.
+   */
+
+  modifyreg32(I2S_OUT_LINK_REG(priv->config->port), I2S_OUTLINK_ADDR_M,
+              FIELD_TO_VALUE(I2S_OUTLINK_ADDR,
+              (uintptr_t) bfcontainer->dma_outlink));
+
+  modifyreg32(I2S_OUT_LINK_REG(priv->config->port), I2S_OUTLINK_STOP,
+              I2S_OUTLINK_START);
+
+  modifyreg32(I2S_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_txdma_setup
+ *
+ * Description:
+ *   Setup the next TX DMA transfer
+ *
+ * Input Parameters:
+ *   priv - I2S state instance
+ *
+ * Returned Value:
+ *   OK on success; a negated errno value on failure
+ *
+ * Assumptions:
+ *   Interrupts are disabled
+ *
+ ****************************************************************************/
+
+#ifdef I2S_HAVE_TX
+static int i2s_txdma_setup(struct esp32_i2s_s *priv,
+                           struct esp32_buffer_s *bfcontainer)
+{
+  struct ap_buffer_s *apb;
+  struct esp32_dmadesc_s *outlink;
+  uintptr_t samp;
+  apb_samp_t nbytes;
+  uint32_t bytes_queued;
+
+  DEBUGASSERT(bfcontainer && bfcontainer->apb);
+
+  apb = bfcontainer->apb;
+  outlink = bfcontainer->dma_outlink;
+
+  /* Get the transfer information, accounting for any data offset */
+
+  samp   = (uintptr_t)&apb->samp[apb->curbyte];
+  nbytes = apb->nbytes - apb->curbyte;
+
+  /* Configure DMA stream */
+
+  bytes_queued = esp32_dma_init_with_padding(outlink, I2S_DMADESC_NUM,
+                                              (uint8_t *)samp, nbytes,
+                                              &priv->stuff);
+
+  if (bytes_queued != nbytes)
+    {
+      i2serr("Failed to enqueue I2S buffer (%d bytes of %d)\n",
+              bytes_queued, (uint32_t)nbytes);
+      return bytes_queued;
+    }
+
+  /* Add the buffer container to the end of the TX pending queue */
+
+  sq_addlast((sq_entry_t *)bfcontainer, &priv->tx.pend);
+
+  return OK;
+}
+#endif /* I2S_HAVE_TX */
+
+/****************************************************************************
+ * Name: i2s_tx_schedule
+ *
+ * Description:
+ *   An TX DMA completion has occurred.  Schedule processing on
+ *   the working thread.
+ *
+ * Input Parameters:
+ *   handle - The DMA handler
+ *   arg - A pointer to the chip select struction
+ *   result - The result of the DMA transfer
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   - Interrupts are disabled
+ *   - The TX timeout has been canceled.
+ *
+ ****************************************************************************/
+
+#ifdef I2S_HAVE_TX
+static void i2s_tx_schedule(struct esp32_i2s_s *priv,
+                            struct esp32_dmadesc_s *outlink)
+{
+  struct esp32_buffer_s *bfcontainer;
+  struct esp32_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 esp32_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_outlink;
+      while (!(bfdesc->ctrl & 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_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 esp32_i2s_s *priv = (struct esp32_i2s_s *)arg;
+  struct esp32_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->lock);
+      bfcontainer = (struct esp32_buffer_s *)sq_remfirst(&priv->tx.done);
+      spin_unlock_irqrestore(&priv->lock, flags);
+
+      /* Perform the TX transfer done callback */
+
+      DEBUGASSERT(bfcontainer && bfcontainer->callback);
+      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_TX */
+
+/****************************************************************************
+ * 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 esp32_i2s_s *priv)
+{
+  /* Set peripheral clock and clear reset */
+
+  modifyreg32(DPORT_PERIP_CLK_EN_REG, 0, DPORT_I2S0_CLK_EN);
+  modifyreg32(DPORT_PERIP_RST_EN_REG, 0, DPORT_I2S0_RST);
+  modifyreg32(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST, 0);
+
+  /* I2S module general init, enable I2S clock */
+
+  if (!(getreg32(I2S_CLKM_CONF_REG(priv->config->port)) & I2S_CLK_ENA))
+    {
+      i2sinfo("Enabling I2S port clock...\n");
+      modifyreg32(I2S_CLKM_CONF_REG(priv->config->port), 0, I2S_CLK_ENA);
+      putreg32(0, I2S_CONF2_REG(priv->config->port));
+    }
+
+  /* Configure multiplexed pins as connected on the board */
+
+  /* TODO: check for loopback mode */
+
+  /* Enable TX channel */
+
+  if (priv->config->dout_pin != I2S_GPIO_UNUSED)
+    {
+      esp32_gpiowrite(priv->config->dout_pin, 1);
+      esp32_configgpio(priv->config->dout_pin, OUTPUT_FUNCTION_3);
+      esp32_gpio_matrix_out(priv->config->dout_pin,
+                              priv->config->dout_outsig, 0, 0);
+    }
+
+  /* TODO: repeat above function for RX channel */
+
+  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 */
+
+          esp32_gpiowrite(priv->config->ws_pin, 1);
+          esp32_configgpio(priv->config->ws_pin, INPUT_FUNCTION_3);
+          esp32_gpio_matrix_out(priv->config->ws_pin,
+                                  priv->config->ws_out_insig, 0, 0);
+
+          esp32_gpiowrite(priv->config->bclk_pin, 1);
+          esp32_configgpio(priv->config->bclk_pin, INPUT_FUNCTION_3);
+          esp32_gpio_matrix_out(priv->config->bclk_pin,
+                                priv->config->bclk_out_insig, 0, 0);
+        }
+      else
+        {
+          /* For "tx + rx + slave" or "rx + slave" mode, select RX signal
+           * index for ws and bck.
+           */
+
+          esp32_gpiowrite(priv->config->ws_pin, 1);
+          esp32_configgpio(priv->config->ws_pin, INPUT_FUNCTION_3);
+          esp32_gpio_matrix_out(priv->config->ws_pin,
+                                  priv->config->ws_in_insig, 0, 0);
+
+          esp32_gpiowrite(priv->config->bclk_pin, 1);
+          esp32_configgpio(priv->config->bclk_pin, INPUT_FUNCTION_3);
+          esp32_gpio_matrix_out(priv->config->bclk_pin,
+                                  priv->config->bclk_in_insig, 0, 0);
+        }
+    }
+  else
+    {
+      /* Considering master role for the I2S port */
+
+      /* Set MCLK pin */
+
+      if (priv->config->mclk_pin != I2S_GPIO_UNUSED)
+        {
+          bool is_i2s0 = priv->config->port == ESP32_I2S0 ? true : false;
+
+          i2sinfo("Configuring GPIO%" PRIu8 " to output master clock\n",
+                  priv->config->mclk_pin);
+
+          esp32_configgpio(priv->config->mclk_pin, OUTPUT_FUNCTION_2);
+          esp32_gpio_matrix_out(priv->config->mclk_pin,
+                                  SIG_GPIO_OUT_IDX, 0, 0);
+
+          if (priv->config->mclk_pin == 0)
+            {
+              putreg32(priv->config->is_apll ?
+                        0xfff6 : (is_i2s0 ? 0xfff0 : 0xffff), PIN_CTRL);
+            }
+          else if (priv->config->mclk_pin == 1)
+            {
+              putreg32(priv->config->is_apll ?
+                        0xf6f6 : (is_i2s0 ? 0xf0f0 : 0xf0ff), PIN_CTRL);
+            }
+          else
+            {
+              putreg32(priv->config->is_apll ?
+                        0xff66 : (is_i2s0 ? 0xff00 : 0xff0f), PIN_CTRL);
+            }
+        }
+
+      if (priv->config->rx_en && !priv->config->tx_en)
+        {
+          /* For "rx + master" mode, select RX signal index for ws and bck */
+
+          esp32_gpiowrite(priv->config->ws_pin, 1);
+          esp32_configgpio(priv->config->ws_pin, OUTPUT_FUNCTION_3);
+          esp32_gpio_matrix_out(priv->config->ws_pin,
+                                  priv->config->ws_in_outsig, 0, 0);
+
+          esp32_gpiowrite(priv->config->bclk_pin, 1);
+          esp32_configgpio(priv->config->bclk_pin, OUTPUT_FUNCTION_3);
+          esp32_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.
+           */
+
+          esp32_gpiowrite(priv->config->ws_pin, 1);
+          esp32_configgpio(priv->config->ws_pin, OUTPUT_FUNCTION_3);
+          esp32_gpio_matrix_out(priv->config->ws_pin,
+                                priv->config->ws_out_outsig, 0, 0);
+
+          esp32_gpiowrite(priv->config->bclk_pin, 1);
+          esp32_configgpio(priv->config->bclk_pin, OUTPUT_FUNCTION_3);
+          esp32_gpio_matrix_out(priv->config->bclk_pin,
+                                priv->config->bclk_out_outsig, 0, 0);
+        }
+    }
+
+  /* TODO: share BCLK and WS if in full-duplex mode */
+
+  /* Configure the hardware to apply STD format */
+
+  if (priv->config->tx_en)
+    {
+      /* Reset I2S TX module */
+
+      modifyreg32(I2S_CONF_REG(priv->config->port), 0, I2S_TX_RESET);
+      modifyreg32(I2S_CONF_REG(priv->config->port), I2S_TX_RESET, 0);
+      modifyreg32(I2S_LC_CONF_REG(priv->config->port), 0, I2S_OUT_RST);
+      modifyreg32(I2S_LC_CONF_REG(priv->config->port), I2S_OUT_RST, 0);
+
+      /* Enable/disable I2S TX slave mode */
+
+      if (priv->config->role == I2S_ROLE_SLAVE)
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port), 0, I2S_TX_SLAVE_MOD);
+        }
+      else
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port), I2S_TX_SLAVE_MOD, 0);
+        }
+
+      /* Congfigure TX chan bit, audio data bit and mono mode.
+       * On ESP32, sample_bit should equals to data_bit
+       */
+
+      /* Set TX data width */
+
+      esp32_i2s_txdatawidth((struct i2s_dev_s *)priv,
+                              priv->config->data_width);
+
+      /* Set I2S tx chan mode */
+
+      modifyreg32(I2S_CONF_CHAN_REG(priv->config->port), I2S_TX_CHAN_MOD_M,
+                  FIELD_TO_VALUE(I2S_TX_CHAN_MOD, priv->config->mono_en ?
+                  4 : 0));
+
+      /* Enable/disable TX MSB shift, the data will be launch at the first
+       * BCK clock.
+       */
+
+      if (priv->config->bit_shift)
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port), 0, I2S_TX_MSB_SHIFT);
+        }
+      else
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port), I2S_TX_MSB_SHIFT, 0);
+        }
+
+      /* Configure TX WS signal width. Set to to enable transmitter in PCM
+       * standard mode.
+       */
+
+      if (priv->config->ws_width == 1)
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port), 0,
+                      I2S_TX_SHORT_SYNC);
+        }
+      else
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port),
+                      I2S_TX_SHORT_SYNC, 0);
+        }
+
+      /* Set I2S tx right channel first */
+
+      if (priv->config->ws_pol == 1)
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port), 0,
+                      I2S_TX_RIGHT_FIRST);
+        }
+      else
+        {
+          modifyreg32(I2S_CONF_REG(priv->config->port),
+                      I2S_TX_RIGHT_FIRST, 0);
+        }
+
+      /* I2S tx fifo module force enable */
+
+      modifyreg32(I2S_FIFO_CONF_REG(priv->config->port), 0,
+                  I2S_TX_FIFO_MOD_FORCE_EN);
+
+      esp32_i2s_txsamplerate((struct i2s_dev_s *)priv, priv->config->rate);
+    }
+
+  /* TODO: check for rx enabled flag */
+}
+
+/****************************************************************************
+ * 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 esp32_i2s_s *priv)
+{
+  /* Reset the TX channel */
+
+  modifyreg32(I2S_CONF_REG(priv->config->port), 0, I2S_TX_RESET);
+  modifyreg32(I2S_CONF_REG(priv->config->port), I2S_TX_RESET, 0);
+
+  /* Reset the DMA operation */
+
+  modifyreg32(I2S_LC_CONF_REG(priv->config->port), 0, I2S_OUT_RST);
+  modifyreg32(I2S_LC_CONF_REG(priv->config->port), I2S_OUT_RST, 0);
+
+  /* Reset TX FIFO */
+
+  modifyreg32(I2S_CONF_REG(priv->config->port), 0, I2S_TX_FIFO_RESET);
+  modifyreg32(I2S_CONF_REG(priv->config->port), I2S_TX_FIFO_RESET, 0);
+
+  /* Enable DMA interruption */
+
+  up_enable_irq(priv->config->irq);
+
+  modifyreg32(I2S_INT_ENA_REG(priv->config->port), UINT32_MAX,
+              I2S_OUT_EOF_INT_ENA);
+
+  /* Enable DMA operation mode */
+
+  modifyreg32(I2S_FIFO_CONF_REG(priv->config->port), 0, I2S_DSCR_EN);
+
+  /* Unset the DMA outlink */
+
+  putreg32(0, I2S_OUT_LINK_REG(priv->config->port));
+
+  i2sinfo("Started TX channel of port %d\n", priv->config->port);
+}
+#endif /* I2S_HAVE_TX */
+
+/****************************************************************************
+ * Name: esp32_i2s_interrupt
+ *
+ * Description:
+ *   Common I2S DMA interrupt handler
+ *
+ * Input Parameters:
+ *   arg - i2s controller private data
+ *
+ * Returned Value:
+ *   Standard interrupt return value.
+ *
+ ****************************************************************************/
+
+static int esp32_i2s_interrupt(int irq, void *context, void *arg)
+{
+  struct esp32_i2s_s *priv = (struct esp32_i2s_s *)arg;
+  struct esp32_dmadesc_s *cur = NULL;
+
+  uint32_t status = getreg32(I2S_INT_ST_REG(priv->config->port));
+
+  putreg32(UINT32_MAX, I2S_INT_CLR_REG(priv->config->port));
+
+  if (status & I2S_OUT_EOF_INT_ST)
+    {
+      cur = (struct esp32_dmadesc_s *)
+            getreg32(I2S_OUT_EOF_DES_ADDR_REG(priv->config->port));
+
+      /* Schedule completion of the transfer to occur on the worker thread */
+
+      i2s_tx_schedule(priv, cur);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: esp32_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
+ *
+ ****************************************************************************/
+
+static uint32_t esp32_i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate)
+{
+  struct esp32_i2s_s *priv = (struct esp32_i2s_s *)dev;
+  uint32_t bclk;
+  uint32_t mclk;
+  uint16_t bclk_div;
+  uint32_t sclk;
+  uint32_t mclk_div;
+  int ma;
+  int mb;
+  int denominator;
+  int numerator;
+  uint32_t regval;
+  uint32_t freq_diff;
+
+  /* TODO: provide APLL clock support */
+
+  /* Disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source
+   * clock.
+   */
+
+  modifyreg32(I2S_CLKM_CONF_REG(priv->config->port), I2S_CLKA_ENA, 0);
+  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 = rate * priv->config->total_slot * priv->data_width;
+      mclk = rate * priv->config->mclk_multiple;
+      bclk_div = mclk / bclk;
+    }
+  else
+    {
+      /* For slave mode, mclk >= bclk * 8, so fix bclk_div to 2 first */
+
+      bclk_div = 8;
+      bclk = 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));
+
+  ma = 0;
+  mb = 0;
+  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.0 / 126.0)
+        {
+          mclk_div++;
+        }
+      else
+        {
+          uint32_t min = ~0;
+
+          for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++)
+            {
+              int b = (int)(a * (freq_diff / (double)mclk) + 0.5);
+              ma = freq_diff * a;
+              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);
+
+  regval = getreg32(I2S_CLKM_CONF_REG(priv->config->port));
+  regval &= ~I2S_CLKM_DIV_NUM_M;
+  regval |= FIELD_TO_VALUE(I2S_CLKM_DIV_NUM, mclk_div);
+  regval &= ~I2S_CLKM_DIV_B_M;
+  regval |= FIELD_TO_VALUE(I2S_CLKM_DIV_B, numerator);
+  regval &= ~I2S_CLKM_DIV_A_M;
+  regval |= FIELD_TO_VALUE(I2S_CLKM_DIV_A, denominator);
+  putreg32(regval, I2S_CLKM_CONF_REG(priv->config->port));
+
+  /* Set I2S tx bck div num */
+
+  modifyreg32(I2S_SAMPLE_RATE_CONF_REG(priv->config->port),
+              I2S_TX_BCK_DIV_NUM_M,
+              FIELD_TO_VALUE(I2S_TX_BCK_DIV_NUM, bclk_div));
+
+  /* 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);
+
+  priv->rate = rate;
+
+  return rate;
+}
+
+/****************************************************************************
+ * Name: esp32_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 bitrate
+ *
+ ****************************************************************************/
+
+static uint32_t esp32_i2s_txdatawidth(struct i2s_dev_s *dev, int bits)
+{
+  struct esp32_i2s_s *priv = (struct esp32_i2s_s *)dev;
+
+  modifyreg32(I2S_SAMPLE_RATE_CONF_REG(priv->config->port),
+              I2S_TX_BITS_MOD_M, FIELD_TO_VALUE(I2S_TX_BITS_MOD, bits));
+
+  priv->data_width = bits;
+
+  /* Set TX FIFO operation mode */
+
+  modifyreg32(I2S_FIFO_CONF_REG(priv->config->port), I2S_TX_FIFO_MOD_M,
+              priv->data_width <= I2S_DATA_BIT_WIDTH_16BIT ?
+              FIELD_TO_VALUE(I2S_TX_FIFO_MOD, 0 + priv->config->mono_en) :
+              FIELD_TO_VALUE(I2S_TX_FIFO_MOD, 2 + priv->config->mono_en));
+
+  /* I2S TX MSB right enable */
+
+  if (priv->data_width <= I2S_DATA_BIT_WIDTH_16BIT)
+    {
+      modifyreg32(I2S_CONF_REG(priv->config->port), 0, I2S_TX_MSB_RIGHT);
+    }
+  else
+    {
+      modifyreg32(I2S_CONF_REG(priv->config->port), I2S_TX_MSB_RIGHT, 0);
+    }
+
+  return bits;
+}
+
+/****************************************************************************
+ * Name: esp32_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.
+ *
+ ****************************************************************************/
+
+static int esp32_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
+                             i2s_callback_t callback, void *arg,
+                             uint32_t timeout)
+{
+  struct esp32_i2s_s *priv = (struct esp32_i2s_s *)dev;
+  struct esp32_buffer_s *bfcontainer;
+  irqstate_t flags;
+  int ret = OK;
+
+  /* Check audio buffer data size */
+
+  if ((apb->nbytes - apb->curbyte) >
+      (ESP32_DMA_DATALEN_MAX * (I2S_DMADESC_NUM - 1)))
+    {
+      return -EFBIG;
+    }
+
+  /* Allocate a buffer container in advance */
+
+  bfcontainer = i2s_buf_allocate(priv);
+  DEBUGASSERT(bfcontainer);
+
+  /* Get exclusive access to the I2S driver data */
+
+  ret = i2s_exclsem_take(priv);
+  if (ret < 0)
+    {
+      goto errout_with_buf;
+    }
+
+  /* Add a reference to the audio buffer */
+
+  apb_reference(apb);
+
+  /* Initialize the buffer container structure */
+
+  bfcontainer->callback = (void *)callback;
+  bfcontainer->timeout  = timeout;
+  bfcontainer->arg      = arg;
+  bfcontainer->apb      = apb;
+  bfcontainer->result   = -EBUSY;
+
+  flags = spin_lock_irqsave(&priv->lock);
+
+  ret = i2s_txdma_setup(priv, bfcontainer);
+
+  if (ret != OK)
+    {
+      goto errout_with_buf;
+    }
+
+  ret = i2s_txdma_start(priv);
+
+  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);
+
+  /* Trigger DMA transfer */
+
+  spin_unlock_irqrestore(&priv->lock, flags);
+  i2s_exclsem_give(priv);
+
+  return OK;
+
+errout_with_buf:
+  i2s_exclsem_give(priv);
+  i2s_buf_free(priv, bfcontainer);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32_i2sdma_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 esp32_i2sdma_setup(struct esp32_i2s_s *priv)
+{
+  int ret;
+
+  /* Clear the interrupts */
+
+  putreg32(UINT32_MAX, I2S_INT_CLR_REG(priv->config->port));
+
+  /* Set up to receive peripheral interrupts on the current CPU */
+
+  priv->cpu = up_cpu_index();
+  priv->cpuint = esp32_setup_irq(priv->cpu, priv->config->periph,
+                                  1, ESP32_CPUINT_LEVEL);
+  if (priv->cpuint < 0)
+    {
+      i2serr("Failed to allocate a CPU interrupt.\n");
+      return priv->cpuint;
+    }
+
+  ret = irq_attach(priv->config->irq, esp32_i2s_interrupt, priv);
+  if (ret != OK)
+    {
+      i2serr("Couldn't attach IRQ to handler.\n");
+      esp32_teardown_irq(priv->cpu,
+                          priv->config->periph,
+                          priv->cpuint);
+      return ret;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp32_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 *esp32_i2sbus_initialize(int port)
+{
+  int ret;
+  struct esp32_i2s_s *priv = NULL;
+  irqstate_t flags;
+
+  i2sinfo("port: %d\n", port);
+
+  /* Statically allocated I2S' device strucuture */
+
+  switch (port)
+    {
+#ifdef CONFIG_ESP32_I2S0
+      case ESP32_I2S0:
+        priv = &esp32_i2s0_priv;
+        break;
+#endif
+#ifdef CONFIG_ESP32_I2S1
+      case ESP32_I2S1:
+        priv = &esp32_i2s1_priv;
+        break;
+#endif
+      default:
+        return NULL;
+    }
+
+  flags = spin_lock_irqsave(&priv->lock);
+
+  nxsem_init(&priv->exclsem, 0, 1);
+
+  i2s_configure(priv);
+
+  /* Allocate buffer containers */
+
+  ret = i2s_buf_initialize(priv);
+  if (ret < 0)
+    {
+      goto err;
+    }
+
+  ret = esp32_i2sdma_setup(priv);
+  if (ret < 0)
+    {
+      goto err;
+    }
+
+#ifdef I2S_HAVE_TX
+  /* Start TX channel */
+
+  i2s_tx_channel_start(priv);
+#endif /* I2S_HAVE_TX */
+
+  spin_unlock_irqrestore(&priv->lock, flags);
+
+  /* Success exit */
+
+  i2sinfo("I2S%d was successfully initialized\n", priv->config->port);
+
+  return &priv->dev;
+
+  /* Failure exit */
+
+err:
+  spin_unlock_irqrestore(&priv->lock, flags);
+  nxsem_destroy(&priv->exclsem);
+  return NULL;
+}
+
+#endif /* CONFIG_ESP32_I2S */
diff --git a/arch/xtensa/src/esp32/esp32_dma.h 
b/arch/xtensa/src/esp32/esp32_i2s.h
similarity index 56%
copy from arch/xtensa/src/esp32/esp32_dma.h
copy to arch/xtensa/src/esp32/esp32_i2s.h
index 1768da02b3..6ee13bb279 100644
--- a/arch/xtensa/src/esp32/esp32_dma.h
+++ b/arch/xtensa/src/esp32/esp32_i2s.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/xtensa/src/esp32/esp32_dma.h
+ * arch/xtensa/src/esp32/esp32_i2s.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,15 +18,15 @@
  *
  ****************************************************************************/
 
+#ifndef __ARCH_XTENSA_SRC_ESP32_ESP32_I2S_H
+#define __ARCH_XTENSA_SRC_ESP32_ESP32_I2S_H
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
-#ifndef __ARCH_XTENSA_SRC_ESP32_ESP32_DMA_H
-#define __ARCH_XTENSA_SRC_ESP32_ESP32_DMA_H
-
 #include <nuttx/config.h>
-#include <stdint.h>
+#include <nuttx/audio/i2s.h>
 
 #ifndef __ASSEMBLY__
 
@@ -39,60 +39,42 @@ extern "C"
 #define EXTERN extern
 #endif
 
-/****************************************************************************
- * Pre-processor Macros
- ****************************************************************************/
-
-/* DMA max data length */
-
-#define ESP32_DMA_DATALEN_MAX       (0x1000 - 4)
+#ifdef CONFIG_ESP32_I2S
 
-/* DMA max buffer length */
+#ifdef CONFIG_ESP32_I2S0
+  #define ESP32_I2S0 0
+#endif /* CONFIG_ESP32_I2S0 */
 
-#define ESP32_DMA_BUFLEN_MAX        ESP32_DMA_DATALEN_MAX
-
-/****************************************************************************
- * Public Types
- ****************************************************************************/
-
-/* DMA description type */
-
-struct esp32_dmadesc_s
-{
-  uint32_t ctrl;                    /* DMA control block */
-  uint8_t *pbuf;                    /* DMA TX/RX buffer address */
-  struct esp32_dmadesc_s *next;     /* Next DMA description address */
-};
+#ifdef CONFIG_ESP32_I2S1
+  #define ESP32_I2S1 1
+#endif /* CONFIG_ESP32_I2S1 */
 
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Name: esp32_dma_init
+ * Name: esp32_i2sbus_initialize
  *
  * Description:
- *   Initialize ESP32 DMA descriptions and bind the target
- *   buffer to these ESP32 DMA descriptions.
+ *   Initialize the selected I2S port
  *
  * Input Parameters:
- *   dmadesc - DMA descriptions pointer
- *   num     - DMA descriptions number
- *   pbuf    - RX/TX buffer pointer
- *   len     - RX/TX buffer length
+ *   Port number (for hardware that has multiple I2S interfaces)
  *
  * Returned Value:
- *   Bind pbuf data bytes
+ *   Valid I2S device structure reference on success; a NULL on failure
  *
  ****************************************************************************/
 
-uint32_t esp32_dma_init(struct esp32_dmadesc_s *dmadesc, uint32_t num,
-                        uint8_t *pbuf, uint32_t len);
+struct i2s_dev_s *esp32_i2sbus_initialize(int port);
 
+#endif /* CONFIG_ESP32_I2S */
+
+#undef EXTERN
 #ifdef __cplusplus
 }
 #endif
-#undef EXTERN
 
 #endif /* __ASSEMBLY__ */
-#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_DMA_H */
+#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_I2S_H */
diff --git a/arch/xtensa/src/esp32/hardware/esp32_i2s.h 
b/arch/xtensa/src/esp32/hardware/esp32_i2s.h
index 4acb1cef53..ca3d67cfc7 100644
--- a/arch/xtensa/src/esp32/hardware/esp32_i2s.h
+++ b/arch/xtensa/src/esp32/hardware/esp32_i2s.h
@@ -18,30 +18,2039 @@
  *
  ****************************************************************************/
 
+#ifndef __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_I2S_H
+#define __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_I2S_H
+
 /****************************************************************************
- * Included Files
+ * Pre-processor Definitions
  ****************************************************************************/
 
-#ifndef __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_I2S_H
-#define __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_I2S_H
+#define REG_I2S_BASE(i) (DR_REG_I2S_BASE + ((i)*0x1e000))
+
+/* I2S_CONF_REG register
+ * I2S Configure register
+ */
+
+#define I2S_CONF_REG(i) (REG_I2S_BASE(i)  + 0x8)
+
+/* I2S_SIG_LOOPBACK : R/W; bitpos: [18]; default: 0;
+ * Enable signal loopback mode with transmitter module and receiver module
+ * sharing the same WS and BCK signals.
+ */
+
+#define I2S_SIG_LOOPBACK    (BIT(18))
+#define I2S_SIG_LOOPBACK_M  (I2S_SIG_LOOPBACK_V << I2S_SIG_LOOPBACK_S)
+#define I2S_SIG_LOOPBACK_V  0x00000001
+#define I2S_SIG_LOOPBACK_S  18
+
+/* I2S_RX_MSB_RIGHT : R/W; bitpos: [17]; default: 0;
+ * Set this bit to place right channel data at the MSB in the receive FIFO.
+ */
+
+#define I2S_RX_MSB_RIGHT    (BIT(17))
+#define I2S_RX_MSB_RIGHT_M  (I2S_RX_MSB_RIGHT_V << I2S_RX_MSB_RIGHT_S)
+#define I2S_RX_MSB_RIGHT_V  0x00000001
+#define I2S_RX_MSB_RIGHT_S  17
+
+/* I2S_TX_MSB_RIGHT : R/W; bitpos: [16]; default: 0;
+ * Set this bit to place right channel data at the MSB in the transmit FIFO.
+ */
+
+#define I2S_TX_MSB_RIGHT    (BIT(16))
+#define I2S_TX_MSB_RIGHT_M  (I2S_TX_MSB_RIGHT_V << I2S_TX_MSB_RIGHT_S)
+#define I2S_TX_MSB_RIGHT_V  0x00000001
+#define I2S_TX_MSB_RIGHT_S  16
+
+/* I2S_RX_MONO : R/W; bitpos: [15]; default: 0;
+ * Set this bit to enable receiver  in mono mode
+ */
+
+#define I2S_RX_MONO    (BIT(15))
+#define I2S_RX_MONO_M  (I2S_RX_MONO_V << I2S_RX_MONO_S)
+#define I2S_RX_MONO_V  0x00000001
+#define I2S_RX_MONO_S  15
+
+/* I2S_TX_MONO : R/W; bitpos: [14]; default: 0;
+ * Set this bit to enable transmitter in mono mode
+ */
+
+#define I2S_TX_MONO    (BIT(14))
+#define I2S_TX_MONO_M  (I2S_TX_MONO_V << I2S_TX_MONO_S)
+#define I2S_TX_MONO_V  0x00000001
+#define I2S_TX_MONO_S  14
+
+/* I2S_RX_SHORT_SYNC : R/W; bitpos: [13]; default: 0;
+ * Set this bit to enable receiver in PCM standard mode
+ */
+
+#define I2S_RX_SHORT_SYNC    (BIT(13))
+#define I2S_RX_SHORT_SYNC_M  (I2S_RX_SHORT_SYNC_V << I2S_RX_SHORT_SYNC_S)
+#define I2S_RX_SHORT_SYNC_V  0x00000001
+#define I2S_RX_SHORT_SYNC_S  13
+
+/* I2S_TX_SHORT_SYNC : R/W; bitpos: [12]; default: 0;
+ * Set this bit to enable transmitter in PCM standard mode
+ */
+
+#define I2S_TX_SHORT_SYNC    (BIT(12))
+#define I2S_TX_SHORT_SYNC_M  (I2S_TX_SHORT_SYNC_V << I2S_TX_SHORT_SYNC_S)
+#define I2S_TX_SHORT_SYNC_V  0x00000001
+#define I2S_TX_SHORT_SYNC_S  12
+
+/* I2S_RX_MSB_SHIFT : R/W; bitpos: [11]; default: 0;
+ * Set this bit to enable receiver in Phillips standard mode
+ */
+
+#define I2S_RX_MSB_SHIFT    (BIT(11))
+#define I2S_RX_MSB_SHIFT_M  (I2S_RX_MSB_SHIFT_V << I2S_RX_MSB_SHIFT_S)
+#define I2S_RX_MSB_SHIFT_V  0x00000001
+#define I2S_RX_MSB_SHIFT_S  11
+
+/* I2S_TX_MSB_SHIFT : R/W; bitpos: [10]; default: 0;
+ * Set this bit to enable transmitter in Phillips standard mode
+ */
+
+#define I2S_TX_MSB_SHIFT    (BIT(10))
+#define I2S_TX_MSB_SHIFT_M  (I2S_TX_MSB_SHIFT_V << I2S_TX_MSB_SHIFT_S)
+#define I2S_TX_MSB_SHIFT_V  0x00000001
+#define I2S_TX_MSB_SHIFT_S  10
+
+/* I2S_RX_RIGHT_FIRST : R/W; bitpos: [9]; default: 1;
+ * Set this bit to receive right channel data first
+ */
+
+#define I2S_RX_RIGHT_FIRST    (BIT(9))
+#define I2S_RX_RIGHT_FIRST_M  (I2S_RX_RIGHT_FIRST_V << I2S_RX_RIGHT_FIRST_S)
+#define I2S_RX_RIGHT_FIRST_V  0x00000001
+#define I2S_RX_RIGHT_FIRST_S  9
+
+/* I2S_TX_RIGHT_FIRST : R/W; bitpos: [8]; default: 1;
+ * Set this bit to transmit right channel data first
+ */
+
+#define I2S_TX_RIGHT_FIRST    (BIT(8))
+#define I2S_TX_RIGHT_FIRST_M  (I2S_TX_RIGHT_FIRST_V << I2S_TX_RIGHT_FIRST_S)
+#define I2S_TX_RIGHT_FIRST_V  0x00000001
+#define I2S_TX_RIGHT_FIRST_S  8
+
+/* I2S_RX_SLAVE_MOD : R/W; bitpos: [7]; default: 0;
+ * Set this bit to enable slave receiver mode
+ */
+
+#define I2S_RX_SLAVE_MOD    (BIT(7))
+#define I2S_RX_SLAVE_MOD_M  (I2S_RX_SLAVE_MOD_V << I2S_RX_SLAVE_MOD_S)
+#define I2S_RX_SLAVE_MOD_V  0x00000001
+#define I2S_RX_SLAVE_MOD_S  7
+
+/* I2S_TX_SLAVE_MOD : R/W; bitpos: [6]; default: 0;
+ * Set this bit to enable slave transmitter mode
+ */
+
+#define I2S_TX_SLAVE_MOD    (BIT(6))
+#define I2S_TX_SLAVE_MOD_M  (I2S_TX_SLAVE_MOD_V << I2S_TX_SLAVE_MOD_S)
+#define I2S_TX_SLAVE_MOD_V  0x00000001
+#define I2S_TX_SLAVE_MOD_S  6
+
+/* I2S_RX_START : R/W; bitpos: [5]; default: 0;
+ * Set this bit to start receiving data
+ */
+
+#define I2S_RX_START    (BIT(5))
+#define I2S_RX_START_M  (I2S_RX_START_V << I2S_RX_START_S)
+#define I2S_RX_START_V  0x00000001
+#define I2S_RX_START_S  5
+
+/* I2S_TX_START : R/W; bitpos: [4]; default: 0;
+ * Set this bit to start transmitting data
+ */
+
+#define I2S_TX_START    (BIT(4))
+#define I2S_TX_START_M  (I2S_TX_START_V << I2S_TX_START_S)
+#define I2S_TX_START_V  0x00000001
+#define I2S_TX_START_S  4
+
+/* I2S_RX_FIFO_RESET : WO; bitpos: [3]; default: 0;
+ * Set this bit to reset rxFIFO
+ */
+
+#define I2S_RX_FIFO_RESET    (BIT(3))
+#define I2S_RX_FIFO_RESET_M  (I2S_RX_FIFO_RESET_V << I2S_RX_FIFO_RESET_S)
+#define I2S_RX_FIFO_RESET_V  0x00000001
+#define I2S_RX_FIFO_RESET_S  3
+
+/* I2S_TX_FIFO_RESET : WO; bitpos: [2]; default: 0;
+ * Set this bit to reset txFIFO
+ */
+
+#define I2S_TX_FIFO_RESET    (BIT(2))
+#define I2S_TX_FIFO_RESET_M  (I2S_TX_FIFO_RESET_V << I2S_TX_FIFO_RESET_S)
+#define I2S_TX_FIFO_RESET_V  0x00000001
+#define I2S_TX_FIFO_RESET_S  2
+
+/* I2S_RX_RESET : WO; bitpos: [1]; default: 0;
+ * Set this bit to reset receiver
+ */
+
+#define I2S_RX_RESET    (BIT(1))
+#define I2S_RX_RESET_M  (I2S_RX_RESET_V << I2S_RX_RESET_S)
+#define I2S_RX_RESET_V  0x00000001
+#define I2S_RX_RESET_S  1
+
+/* I2S_TX_RESET : WO; bitpos: [0]; default: 0;
+ * Set this bit to reset transmitter
+ */
+
+#define I2S_TX_RESET    (BIT(0))
+#define I2S_TX_RESET_M  (I2S_TX_RESET_V << I2S_TX_RESET_S)
+#define I2S_TX_RESET_V  0x00000001
+#define I2S_TX_RESET_S  0
+
+/* I2S_INT_RAW_REG register
+ * Raw interrupt status
+ */
+
+#define I2S_INT_RAW_REG(i) (REG_I2S_BASE(i) + 0xc)
+
+/* I2S_OUT_TOTAL_EOF_INT_RAW : RO; bitpos: [16]; default: 0;
+ * The raw interrupt status bit  for the i2s_out_total_eof_int interrupt
+ */
+
+#define I2S_OUT_TOTAL_EOF_INT_RAW    (BIT(16))
+#define I2S_OUT_TOTAL_EOF_INT_RAW_M  (I2S_OUT_TOTAL_EOF_INT_RAW_V << 
I2S_OUT_TOTAL_EOF_INT_RAW_S)
+#define I2S_OUT_TOTAL_EOF_INT_RAW_V  0x00000001
+#define I2S_OUT_TOTAL_EOF_INT_RAW_S  16
+
+/* I2S_IN_DSCR_EMPTY_INT_RAW : RO; bitpos: [15]; default: 0;
+ * The raw interrupt status bit  for the i2s_in_dscr_empty_int interrupt
+ */
+
+#define I2S_IN_DSCR_EMPTY_INT_RAW    (BIT(15))
+#define I2S_IN_DSCR_EMPTY_INT_RAW_M  (I2S_IN_DSCR_EMPTY_INT_RAW_V << 
I2S_IN_DSCR_EMPTY_INT_RAW_S)
+#define I2S_IN_DSCR_EMPTY_INT_RAW_V  0x00000001
+#define I2S_IN_DSCR_EMPTY_INT_RAW_S  15
+
+/* I2S_OUT_DSCR_ERR_INT_RAW : RO; bitpos: [14]; default: 0;
+ * The raw interrupt status bit  for the i2s_out_dscr_err_int interrupt
+ */
+
+#define I2S_OUT_DSCR_ERR_INT_RAW    (BIT(14))
+#define I2S_OUT_DSCR_ERR_INT_RAW_M  (I2S_OUT_DSCR_ERR_INT_RAW_V << 
I2S_OUT_DSCR_ERR_INT_RAW_S)
+#define I2S_OUT_DSCR_ERR_INT_RAW_V  0x00000001
+#define I2S_OUT_DSCR_ERR_INT_RAW_S  14
+
+/* I2S_IN_DSCR_ERR_INT_RAW : RO; bitpos: [13]; default: 0;
+ * The raw interrupt status bit  for the i2s_in_dscr_err_int interrupt
+ */
+
+#define I2S_IN_DSCR_ERR_INT_RAW    (BIT(13))
+#define I2S_IN_DSCR_ERR_INT_RAW_M  (I2S_IN_DSCR_ERR_INT_RAW_V << 
I2S_IN_DSCR_ERR_INT_RAW_S)
+#define I2S_IN_DSCR_ERR_INT_RAW_V  0x00000001
+#define I2S_IN_DSCR_ERR_INT_RAW_S  13
+
+/* I2S_OUT_EOF_INT_RAW : RO; bitpos: [12]; default: 0;
+ * The raw interrupt status bit  for the i2s_out_eof_int interrupt
+ */
+
+#define I2S_OUT_EOF_INT_RAW    (BIT(12))
+#define I2S_OUT_EOF_INT_RAW_M  (I2S_OUT_EOF_INT_RAW_V << I2S_OUT_EOF_INT_RAW_S)
+#define I2S_OUT_EOF_INT_RAW_V  0x00000001
+#define I2S_OUT_EOF_INT_RAW_S  12
+
+/* I2S_OUT_DONE_INT_RAW : RO; bitpos: [11]; default: 0;
+ * The raw interrupt status bit  for the i2s_out_done_int interrupt
+ */
+
+#define I2S_OUT_DONE_INT_RAW    (BIT(11))
+#define I2S_OUT_DONE_INT_RAW_M  (I2S_OUT_DONE_INT_RAW_V << 
I2S_OUT_DONE_INT_RAW_S)
+#define I2S_OUT_DONE_INT_RAW_V  0x00000001
+#define I2S_OUT_DONE_INT_RAW_S  11
+
+/* I2S_IN_ERR_EOF_INT_RAW : RO; bitpos: [10]; default: 0;
+ * don't use
+ */
+
+#define I2S_IN_ERR_EOF_INT_RAW    (BIT(10))
+#define I2S_IN_ERR_EOF_INT_RAW_M  (I2S_IN_ERR_EOF_INT_RAW_V << 
I2S_IN_ERR_EOF_INT_RAW_S)
+#define I2S_IN_ERR_EOF_INT_RAW_V  0x00000001
+#define I2S_IN_ERR_EOF_INT_RAW_S  10
+
+/* I2S_IN_SUC_EOF_INT_RAW : RO; bitpos: [9]; default: 0;
+ * The raw interrupt status bit  for the i2s_in_suc_eof_int interrupt
+ */
+
+#define I2S_IN_SUC_EOF_INT_RAW    (BIT(9))
+#define I2S_IN_SUC_EOF_INT_RAW_M  (I2S_IN_SUC_EOF_INT_RAW_V << 
I2S_IN_SUC_EOF_INT_RAW_S)
+#define I2S_IN_SUC_EOF_INT_RAW_V  0x00000001
+#define I2S_IN_SUC_EOF_INT_RAW_S  9
+
+/* I2S_IN_DONE_INT_RAW : RO; bitpos: [8]; default: 0;
+ * The raw interrupt status bit  for the i2s_in_done_int interrupt
+ */
+
+#define I2S_IN_DONE_INT_RAW    (BIT(8))
+#define I2S_IN_DONE_INT_RAW_M  (I2S_IN_DONE_INT_RAW_V << I2S_IN_DONE_INT_RAW_S)
+#define I2S_IN_DONE_INT_RAW_V  0x00000001
+#define I2S_IN_DONE_INT_RAW_S  8
+
+/* I2S_TX_HUNG_INT_RAW : RO; bitpos: [7]; default: 0;
+ * The raw interrupt status bit  for the i2s_tx_hung_int interrupt
+ */
+
+#define I2S_TX_HUNG_INT_RAW    (BIT(7))
+#define I2S_TX_HUNG_INT_RAW_M  (I2S_TX_HUNG_INT_RAW_V << I2S_TX_HUNG_INT_RAW_S)
+#define I2S_TX_HUNG_INT_RAW_V  0x00000001
+#define I2S_TX_HUNG_INT_RAW_S  7
+
+/* I2S_RX_HUNG_INT_RAW : RO; bitpos: [6]; default: 0;
+ * The raw interrupt status bit  for the i2s_rx_hung_int interrupt
+ */
+
+#define I2S_RX_HUNG_INT_RAW    (BIT(6))
+#define I2S_RX_HUNG_INT_RAW_M  (I2S_RX_HUNG_INT_RAW_V << I2S_RX_HUNG_INT_RAW_S)
+#define I2S_RX_HUNG_INT_RAW_V  0x00000001
+#define I2S_RX_HUNG_INT_RAW_S  6
+
+/* I2S_TX_REMPTY_INT_RAW : RO; bitpos: [5]; default: 0;
+ * The raw interrupt status bit  for the i2s_tx_rempty_int interrupt
+ */
+
+#define I2S_TX_REMPTY_INT_RAW    (BIT(5))
+#define I2S_TX_REMPTY_INT_RAW_M  (I2S_TX_REMPTY_INT_RAW_V << 
I2S_TX_REMPTY_INT_RAW_S)
+#define I2S_TX_REMPTY_INT_RAW_V  0x00000001
+#define I2S_TX_REMPTY_INT_RAW_S  5
+
+/* I2S_TX_WFULL_INT_RAW : RO; bitpos: [4]; default: 0;
+ * The raw interrupt status bit  for the i2s_tx_wfull_int interrupt
+ */
+
+#define I2S_TX_WFULL_INT_RAW    (BIT(4))
+#define I2S_TX_WFULL_INT_RAW_M  (I2S_TX_WFULL_INT_RAW_V << 
I2S_TX_WFULL_INT_RAW_S)
+#define I2S_TX_WFULL_INT_RAW_V  0x00000001
+#define I2S_TX_WFULL_INT_RAW_S  4
+
+/* I2S_RX_REMPTY_INT_RAW : RO; bitpos: [3]; default: 0;
+ * The raw interrupt status bit  for the i2s_rx_rempty_int interrupt
+ */
+
+#define I2S_RX_REMPTY_INT_RAW    (BIT(3))
+#define I2S_RX_REMPTY_INT_RAW_M  (I2S_RX_REMPTY_INT_RAW_V << 
I2S_RX_REMPTY_INT_RAW_S)
+#define I2S_RX_REMPTY_INT_RAW_V  0x00000001
+#define I2S_RX_REMPTY_INT_RAW_S  3
+
+/* I2S_RX_WFULL_INT_RAW : RO; bitpos: [2]; default: 0;
+ * The raw interrupt status bit  for the i2s_rx_wfull_int interrupt
+ */
+
+#define I2S_RX_WFULL_INT_RAW    (BIT(2))
+#define I2S_RX_WFULL_INT_RAW_M  (I2S_RX_WFULL_INT_RAW_V << 
I2S_RX_WFULL_INT_RAW_S)
+#define I2S_RX_WFULL_INT_RAW_V  0x00000001
+#define I2S_RX_WFULL_INT_RAW_S  2
+
+/* I2S_TX_PUT_DATA_INT_RAW : RO; bitpos: [1]; default: 0;
+ * The raw interrupt status bit  for the i2s_tx_put_data_int interrupt
+ */
+
+#define I2S_TX_PUT_DATA_INT_RAW    (BIT(1))
+#define I2S_TX_PUT_DATA_INT_RAW_M  (I2S_TX_PUT_DATA_INT_RAW_V << 
I2S_TX_PUT_DATA_INT_RAW_S)
+#define I2S_TX_PUT_DATA_INT_RAW_V  0x00000001
+#define I2S_TX_PUT_DATA_INT_RAW_S  1
+
+/* I2S_RX_TAKE_DATA_INT_RAW : RO; bitpos: [0]; default: 0;
+ * The raw interrupt status bit  for the i2s_rx_take_data_int interrupt
+ */
+
+#define I2S_RX_TAKE_DATA_INT_RAW    (BIT(0))
+#define I2S_RX_TAKE_DATA_INT_RAW_M  (I2S_RX_TAKE_DATA_INT_RAW_V << 
I2S_RX_TAKE_DATA_INT_RAW_S)
+#define I2S_RX_TAKE_DATA_INT_RAW_V  0x00000001
+#define I2S_RX_TAKE_DATA_INT_RAW_S  0
+
+/* I2S_INT_ST_REG register
+ * Masked interrupt status
+ */
+
+#define I2S_INT_ST_REG(i) (REG_I2S_BASE(i) + 0x10)
+
+/* I2S_OUT_TOTAL_EOF_INT_ST : RO; bitpos: [16]; default: 0;
+ * The masked interrupt status bit  for the i2s_out_total_eof_int interrupt
+ */
+
+#define I2S_OUT_TOTAL_EOF_INT_ST    (BIT(16))
+#define I2S_OUT_TOTAL_EOF_INT_ST_M  (I2S_OUT_TOTAL_EOF_INT_ST_V << 
I2S_OUT_TOTAL_EOF_INT_ST_S)
+#define I2S_OUT_TOTAL_EOF_INT_ST_V  0x00000001
+#define I2S_OUT_TOTAL_EOF_INT_ST_S  16
+
+/* I2S_IN_DSCR_EMPTY_INT_ST : RO; bitpos: [15]; default: 0;
+ * The masked interrupt status bit  for the i2s_in_dscr_empty_int interrupt
+ */
+
+#define I2S_IN_DSCR_EMPTY_INT_ST    (BIT(15))
+#define I2S_IN_DSCR_EMPTY_INT_ST_M  (I2S_IN_DSCR_EMPTY_INT_ST_V << 
I2S_IN_DSCR_EMPTY_INT_ST_S)
+#define I2S_IN_DSCR_EMPTY_INT_ST_V  0x00000001
+#define I2S_IN_DSCR_EMPTY_INT_ST_S  15
+
+/* I2S_OUT_DSCR_ERR_INT_ST : RO; bitpos: [14]; default: 0;
+ * The masked interrupt status bit  for the i2s_out_dscr_err_int interrupt
+ */
+
+#define I2S_OUT_DSCR_ERR_INT_ST    (BIT(14))
+#define I2S_OUT_DSCR_ERR_INT_ST_M  (I2S_OUT_DSCR_ERR_INT_ST_V << 
I2S_OUT_DSCR_ERR_INT_ST_S)
+#define I2S_OUT_DSCR_ERR_INT_ST_V  0x00000001
+#define I2S_OUT_DSCR_ERR_INT_ST_S  14
+
+/* I2S_IN_DSCR_ERR_INT_ST : RO; bitpos: [13]; default: 0;
+ * The masked interrupt status bit  for the i2s_in_dscr_err_int interrupt
+ */
+
+#define I2S_IN_DSCR_ERR_INT_ST    (BIT(13))
+#define I2S_IN_DSCR_ERR_INT_ST_M  (I2S_IN_DSCR_ERR_INT_ST_V << 
I2S_IN_DSCR_ERR_INT_ST_S)
+#define I2S_IN_DSCR_ERR_INT_ST_V  0x00000001
+#define I2S_IN_DSCR_ERR_INT_ST_S  13
+
+/* I2S_OUT_EOF_INT_ST : RO; bitpos: [12]; default: 0;
+ * The masked interrupt status bit  for the i2s_out_eof_int interrupt
+ */
+
+#define I2S_OUT_EOF_INT_ST    (BIT(12))
+#define I2S_OUT_EOF_INT_ST_M  (I2S_OUT_EOF_INT_ST_V << I2S_OUT_EOF_INT_ST_S)
+#define I2S_OUT_EOF_INT_ST_V  0x00000001
+#define I2S_OUT_EOF_INT_ST_S  12
+
+/* I2S_OUT_DONE_INT_ST : RO; bitpos: [11]; default: 0;
+ * The masked interrupt status bit  for the i2s_out_done_int interrupt
+ */
+
+#define I2S_OUT_DONE_INT_ST    (BIT(11))
+#define I2S_OUT_DONE_INT_ST_M  (I2S_OUT_DONE_INT_ST_V << I2S_OUT_DONE_INT_ST_S)
+#define I2S_OUT_DONE_INT_ST_V  0x00000001
+#define I2S_OUT_DONE_INT_ST_S  11
+
+/* I2S_IN_ERR_EOF_INT_ST : RO; bitpos: [10]; default: 0;
+ * don't use
+ */
+
+#define I2S_IN_ERR_EOF_INT_ST    (BIT(10))
+#define I2S_IN_ERR_EOF_INT_ST_M  (I2S_IN_ERR_EOF_INT_ST_V << 
I2S_IN_ERR_EOF_INT_ST_S)
+#define I2S_IN_ERR_EOF_INT_ST_V  0x00000001
+#define I2S_IN_ERR_EOF_INT_ST_S  10
+
+/* I2S_IN_SUC_EOF_INT_ST : RO; bitpos: [9]; default: 0;
+ * The masked interrupt status bit  for the i2s_in_suc_eof_int interrupt
+ */
+
+#define I2S_IN_SUC_EOF_INT_ST    (BIT(9))
+#define I2S_IN_SUC_EOF_INT_ST_M  (I2S_IN_SUC_EOF_INT_ST_V << 
I2S_IN_SUC_EOF_INT_ST_S)
+#define I2S_IN_SUC_EOF_INT_ST_V  0x00000001
+#define I2S_IN_SUC_EOF_INT_ST_S  9
+
+/* I2S_IN_DONE_INT_ST : RO; bitpos: [8]; default: 0;
+ * The masked interrupt status bit  for the i2s_in_done_int interrupt
+ */
+
+#define I2S_IN_DONE_INT_ST    (BIT(8))
+#define I2S_IN_DONE_INT_ST_M  (I2S_IN_DONE_INT_ST_V << I2S_IN_DONE_INT_ST_S)
+#define I2S_IN_DONE_INT_ST_V  0x00000001
+#define I2S_IN_DONE_INT_ST_S  8
+
+/* I2S_TX_HUNG_INT_ST : RO; bitpos: [7]; default: 0;
+ * The masked interrupt status bit  for the i2s_tx_hung_int interrupt
+ */
+
+#define I2S_TX_HUNG_INT_ST    (BIT(7))
+#define I2S_TX_HUNG_INT_ST_M  (I2S_TX_HUNG_INT_ST_V << I2S_TX_HUNG_INT_ST_S)
+#define I2S_TX_HUNG_INT_ST_V  0x00000001
+#define I2S_TX_HUNG_INT_ST_S  7
+
+/* I2S_RX_HUNG_INT_ST : RO; bitpos: [6]; default: 0;
+ * The masked interrupt status bit  for the i2s_rx_hung_int interrupt
+ */
+
+#define I2S_RX_HUNG_INT_ST    (BIT(6))
+#define I2S_RX_HUNG_INT_ST_M  (I2S_RX_HUNG_INT_ST_V << I2S_RX_HUNG_INT_ST_S)
+#define I2S_RX_HUNG_INT_ST_V  0x00000001
+#define I2S_RX_HUNG_INT_ST_S  6
+
+/* I2S_TX_REMPTY_INT_ST : RO; bitpos: [5]; default: 0;
+ * The masked interrupt status bit  for the i2s_tx_rempty_int interrupt
+ */
+
+#define I2S_TX_REMPTY_INT_ST    (BIT(5))
+#define I2S_TX_REMPTY_INT_ST_M  (I2S_TX_REMPTY_INT_ST_V << 
I2S_TX_REMPTY_INT_ST_S)
+#define I2S_TX_REMPTY_INT_ST_V  0x00000001
+#define I2S_TX_REMPTY_INT_ST_S  5
+
+/* I2S_TX_WFULL_INT_ST : RO; bitpos: [4]; default: 0;
+ * The masked interrupt status bit  for the i2s_tx_wfull_int interrupt
+ */
+
+#define I2S_TX_WFULL_INT_ST    (BIT(4))
+#define I2S_TX_WFULL_INT_ST_M  (I2S_TX_WFULL_INT_ST_V << I2S_TX_WFULL_INT_ST_S)
+#define I2S_TX_WFULL_INT_ST_V  0x00000001
+#define I2S_TX_WFULL_INT_ST_S  4
+
+/* I2S_RX_REMPTY_INT_ST : RO; bitpos: [3]; default: 0;
+ * The masked interrupt status bit  for the i2s_rx_rempty_int interrupt
+ */
+
+#define I2S_RX_REMPTY_INT_ST    (BIT(3))
+#define I2S_RX_REMPTY_INT_ST_M  (I2S_RX_REMPTY_INT_ST_V << 
I2S_RX_REMPTY_INT_ST_S)
+#define I2S_RX_REMPTY_INT_ST_V  0x00000001
+#define I2S_RX_REMPTY_INT_ST_S  3
+
+/* I2S_RX_WFULL_INT_ST : RO; bitpos: [2]; default: 0;
+ * The masked interrupt status bit  for the i2s_rx_wfull_int interrupt
+ */
+
+#define I2S_RX_WFULL_INT_ST    (BIT(2))
+#define I2S_RX_WFULL_INT_ST_M  (I2S_RX_WFULL_INT_ST_V << I2S_RX_WFULL_INT_ST_S)
+#define I2S_RX_WFULL_INT_ST_V  0x00000001
+#define I2S_RX_WFULL_INT_ST_S  2
+
+/* I2S_TX_PUT_DATA_INT_ST : RO; bitpos: [1]; default: 0;
+ * The masked interrupt status bit  for the i2s_tx_put_data_int interrupt
+ */
+
+#define I2S_TX_PUT_DATA_INT_ST    (BIT(1))
+#define I2S_TX_PUT_DATA_INT_ST_M  (I2S_TX_PUT_DATA_INT_ST_V << 
I2S_TX_PUT_DATA_INT_ST_S)
+#define I2S_TX_PUT_DATA_INT_ST_V  0x00000001
+#define I2S_TX_PUT_DATA_INT_ST_S  1
+
+/* I2S_RX_TAKE_DATA_INT_ST : RO; bitpos: [0]; default: 0;
+ * The masked interrupt status bit  for the i2s_rx_take_data_int interrupt
+ */
+
+#define I2S_RX_TAKE_DATA_INT_ST    (BIT(0))
+#define I2S_RX_TAKE_DATA_INT_ST_M  (I2S_RX_TAKE_DATA_INT_ST_V << 
I2S_RX_TAKE_DATA_INT_ST_S)
+#define I2S_RX_TAKE_DATA_INT_ST_V  0x00000001
+#define I2S_RX_TAKE_DATA_INT_ST_S  0
+
+/* I2S_INT_ENA_REG register
+ * Interrupt enable bits
+ */
+
+#define I2S_INT_ENA_REG(i) (REG_I2S_BASE(i) + 0x14)
+
+/* I2S_OUT_TOTAL_EOF_INT_ENA : R/W; bitpos: [16]; default: 0;
+ * The interrupt enable bit  for the i2s_out_total_eof_int interrupt
+ */
+
+#define I2S_OUT_TOTAL_EOF_INT_ENA    (BIT(16))
+#define I2S_OUT_TOTAL_EOF_INT_ENA_M  (I2S_OUT_TOTAL_EOF_INT_ENA_V << 
I2S_OUT_TOTAL_EOF_INT_ENA_S)
+#define I2S_OUT_TOTAL_EOF_INT_ENA_V  0x00000001
+#define I2S_OUT_TOTAL_EOF_INT_ENA_S  16
+
+/* I2S_IN_DSCR_EMPTY_INT_ENA : R/W; bitpos: [15]; default: 0;
+ * The interrupt enable bit  for the i2s_in_dscr_empty_int interrupt
+ */
+
+#define I2S_IN_DSCR_EMPTY_INT_ENA    (BIT(15))
+#define I2S_IN_DSCR_EMPTY_INT_ENA_M  (I2S_IN_DSCR_EMPTY_INT_ENA_V << 
I2S_IN_DSCR_EMPTY_INT_ENA_S)
+#define I2S_IN_DSCR_EMPTY_INT_ENA_V  0x00000001
+#define I2S_IN_DSCR_EMPTY_INT_ENA_S  15
+
+/* I2S_OUT_DSCR_ERR_INT_ENA : R/W; bitpos: [14]; default: 0;
+ * The interrupt enable bit  for the i2s_out_dscr_err_int interrupt
+ */
+
+#define I2S_OUT_DSCR_ERR_INT_ENA    (BIT(14))
+#define I2S_OUT_DSCR_ERR_INT_ENA_M  (I2S_OUT_DSCR_ERR_INT_ENA_V << 
I2S_OUT_DSCR_ERR_INT_ENA_S)
+#define I2S_OUT_DSCR_ERR_INT_ENA_V  0x00000001
+#define I2S_OUT_DSCR_ERR_INT_ENA_S  14
+
+/* I2S_IN_DSCR_ERR_INT_ENA : R/W; bitpos: [13]; default: 0;
+ * The interrupt enable bit  for the i2s_in_dscr_err_int interrupt
+ */
+
+#define I2S_IN_DSCR_ERR_INT_ENA    (BIT(13))
+#define I2S_IN_DSCR_ERR_INT_ENA_M  (I2S_IN_DSCR_ERR_INT_ENA_V << 
I2S_IN_DSCR_ERR_INT_ENA_S)
+#define I2S_IN_DSCR_ERR_INT_ENA_V  0x00000001
+#define I2S_IN_DSCR_ERR_INT_ENA_S  13
+
+/* I2S_OUT_EOF_INT_ENA : R/W; bitpos: [12]; default: 0;
+ * The interrupt enable bit  for the i2s_out_eof_int interrupt
+ */
+
+#define I2S_OUT_EOF_INT_ENA    (BIT(12))
+#define I2S_OUT_EOF_INT_ENA_M  (I2S_OUT_EOF_INT_ENA_V << I2S_OUT_EOF_INT_ENA_S)
+#define I2S_OUT_EOF_INT_ENA_V  0x00000001
+#define I2S_OUT_EOF_INT_ENA_S  12
+
+/* I2S_OUT_DONE_INT_ENA : R/W; bitpos: [11]; default: 0;
+ * The interrupt enable bit  for the i2s_out_done_int interrupt
+ */
+
+#define I2S_OUT_DONE_INT_ENA    (BIT(11))
+#define I2S_OUT_DONE_INT_ENA_M  (I2S_OUT_DONE_INT_ENA_V << 
I2S_OUT_DONE_INT_ENA_S)
+#define I2S_OUT_DONE_INT_ENA_V  0x00000001
+#define I2S_OUT_DONE_INT_ENA_S  11
+
+/* I2S_IN_ERR_EOF_INT_ENA : R/W; bitpos: [10]; default: 0;
+ * don't use
+ */
+
+#define I2S_IN_ERR_EOF_INT_ENA    (BIT(10))
+#define I2S_IN_ERR_EOF_INT_ENA_M  (I2S_IN_ERR_EOF_INT_ENA_V << 
I2S_IN_ERR_EOF_INT_ENA_S)
+#define I2S_IN_ERR_EOF_INT_ENA_V  0x00000001
+#define I2S_IN_ERR_EOF_INT_ENA_S  10
+
+/* I2S_IN_SUC_EOF_INT_ENA : R/W; bitpos: [9]; default: 0;
+ * The interrupt enable bit  for the i2s_in_suc_eof_int interrupt
+ */
+
+#define I2S_IN_SUC_EOF_INT_ENA    (BIT(9))
+#define I2S_IN_SUC_EOF_INT_ENA_M  (I2S_IN_SUC_EOF_INT_ENA_V << 
I2S_IN_SUC_EOF_INT_ENA_S)
+#define I2S_IN_SUC_EOF_INT_ENA_V  0x00000001
+#define I2S_IN_SUC_EOF_INT_ENA_S  9
+
+/* I2S_IN_DONE_INT_ENA : R/W; bitpos: [8]; default: 0;
+ * The interrupt enable bit  for the i2s_in_done_int interrupt
+ */
+
+#define I2S_IN_DONE_INT_ENA    (BIT(8))
+#define I2S_IN_DONE_INT_ENA_M  (I2S_IN_DONE_INT_ENA_V << I2S_IN_DONE_INT_ENA_S)
+#define I2S_IN_DONE_INT_ENA_V  0x00000001
+#define I2S_IN_DONE_INT_ENA_S  8
+
+/* I2S_TX_HUNG_INT_ENA : R/W; bitpos: [7]; default: 0;
+ * The interrupt enable bit  for the i2s_tx_hung_int interrupt
+ */
+
+#define I2S_TX_HUNG_INT_ENA    (BIT(7))
+#define I2S_TX_HUNG_INT_ENA_M  (I2S_TX_HUNG_INT_ENA_V << I2S_TX_HUNG_INT_ENA_S)
+#define I2S_TX_HUNG_INT_ENA_V  0x00000001
+#define I2S_TX_HUNG_INT_ENA_S  7
+
+/* I2S_RX_HUNG_INT_ENA : R/W; bitpos: [6]; default: 0;
+ * The interrupt enable bit  for the i2s_rx_hung_int interrupt
+ */
+
+#define I2S_RX_HUNG_INT_ENA    (BIT(6))
+#define I2S_RX_HUNG_INT_ENA_M  (I2S_RX_HUNG_INT_ENA_V << I2S_RX_HUNG_INT_ENA_S)
+#define I2S_RX_HUNG_INT_ENA_V  0x00000001
+#define I2S_RX_HUNG_INT_ENA_S  6
+
+/* I2S_TX_REMPTY_INT_ENA : R/W; bitpos: [5]; default: 0;
+ * The interrupt enable bit  for the i2s_tx_rempty_int interrupt
+ */
+
+#define I2S_TX_REMPTY_INT_ENA    (BIT(5))
+#define I2S_TX_REMPTY_INT_ENA_M  (I2S_TX_REMPTY_INT_ENA_V << 
I2S_TX_REMPTY_INT_ENA_S)
+#define I2S_TX_REMPTY_INT_ENA_V  0x00000001
+#define I2S_TX_REMPTY_INT_ENA_S  5
+
+/* I2S_TX_WFULL_INT_ENA : R/W; bitpos: [4]; default: 0;
+ * The interrupt enable bit  for the i2s_tx_wfull_int interrupt
+ */
+
+#define I2S_TX_WFULL_INT_ENA    (BIT(4))
+#define I2S_TX_WFULL_INT_ENA_M  (I2S_TX_WFULL_INT_ENA_V << 
I2S_TX_WFULL_INT_ENA_S)
+#define I2S_TX_WFULL_INT_ENA_V  0x00000001
+#define I2S_TX_WFULL_INT_ENA_S  4
+
+/* I2S_RX_REMPTY_INT_ENA : R/W; bitpos: [3]; default: 0;
+ * The interrupt enable bit  for the i2s_rx_rempty_int interrupt
+ */
+
+#define I2S_RX_REMPTY_INT_ENA    (BIT(3))
+#define I2S_RX_REMPTY_INT_ENA_M  (I2S_RX_REMPTY_INT_ENA_V << 
I2S_RX_REMPTY_INT_ENA_S)
+#define I2S_RX_REMPTY_INT_ENA_V  0x00000001
+#define I2S_RX_REMPTY_INT_ENA_S  3
+
+/* I2S_RX_WFULL_INT_ENA : R/W; bitpos: [2]; default: 0;
+ * The interrupt enable bit  for the i2s_rx_wfull_int interrupt
+ */
+
+#define I2S_RX_WFULL_INT_ENA    (BIT(2))
+#define I2S_RX_WFULL_INT_ENA_M  (I2S_RX_WFULL_INT_ENA_V << 
I2S_RX_WFULL_INT_ENA_S)
+#define I2S_RX_WFULL_INT_ENA_V  0x00000001
+#define I2S_RX_WFULL_INT_ENA_S  2
+
+/* I2S_TX_PUT_DATA_INT_ENA : R/W; bitpos: [1]; default: 0;
+ * The interrupt enable bit  for the i2s_tx_put_data_int interrupt
+ */
+
+#define I2S_TX_PUT_DATA_INT_ENA    (BIT(1))
+#define I2S_TX_PUT_DATA_INT_ENA_M  (I2S_TX_PUT_DATA_INT_ENA_V << 
I2S_TX_PUT_DATA_INT_ENA_S)
+#define I2S_TX_PUT_DATA_INT_ENA_V  0x00000001
+#define I2S_TX_PUT_DATA_INT_ENA_S  1
+
+/* I2S_RX_TAKE_DATA_INT_ENA : R/W; bitpos: [0]; default: 0;
+ * The interrupt enable bit  for the i2s_rx_take_data_int interrupt
+ */
+
+#define I2S_RX_TAKE_DATA_INT_ENA    (BIT(0))
+#define I2S_RX_TAKE_DATA_INT_ENA_M  (I2S_RX_TAKE_DATA_INT_ENA_V << 
I2S_RX_TAKE_DATA_INT_ENA_S)
+#define I2S_RX_TAKE_DATA_INT_ENA_V  0x00000001
+#define I2S_RX_TAKE_DATA_INT_ENA_S  0
+
+/* I2S_INT_CLR_REG register
+ * Interrupt clear bits
+ */
+
+#define I2S_INT_CLR_REG(i) (REG_I2S_BASE(i) + 0x18)
+
+/* I2S_OUT_TOTAL_EOF_INT_CLR : WO; bitpos: [16]; default: 0;
+ * Set this bit to clear the i2s_out_total_eof_int interrupt
+ */
+
+#define I2S_OUT_TOTAL_EOF_INT_CLR    (BIT(16))
+#define I2S_OUT_TOTAL_EOF_INT_CLR_M  (I2S_OUT_TOTAL_EOF_INT_CLR_V << 
I2S_OUT_TOTAL_EOF_INT_CLR_S)
+#define I2S_OUT_TOTAL_EOF_INT_CLR_V  0x00000001
+#define I2S_OUT_TOTAL_EOF_INT_CLR_S  16
+
+/* I2S_IN_DSCR_EMPTY_INT_CLR : WO; bitpos: [15]; default: 0;
+ * Set this bit to clear the i2s_in_dscr_empty_int interrupt
+ */
+
+#define I2S_IN_DSCR_EMPTY_INT_CLR    (BIT(15))
+#define I2S_IN_DSCR_EMPTY_INT_CLR_M  (I2S_IN_DSCR_EMPTY_INT_CLR_V << 
I2S_IN_DSCR_EMPTY_INT_CLR_S)
+#define I2S_IN_DSCR_EMPTY_INT_CLR_V  0x00000001
+#define I2S_IN_DSCR_EMPTY_INT_CLR_S  15
+
+/* I2S_OUT_DSCR_ERR_INT_CLR : WO; bitpos: [14]; default: 0;
+ * Set this bit to clear the i2s_out_dscr_err_int interrupt
+ */
+
+#define I2S_OUT_DSCR_ERR_INT_CLR    (BIT(14))
+#define I2S_OUT_DSCR_ERR_INT_CLR_M  (I2S_OUT_DSCR_ERR_INT_CLR_V << 
I2S_OUT_DSCR_ERR_INT_CLR_S)
+#define I2S_OUT_DSCR_ERR_INT_CLR_V  0x00000001
+#define I2S_OUT_DSCR_ERR_INT_CLR_S  14
+
+/* I2S_IN_DSCR_ERR_INT_CLR : WO; bitpos: [13]; default: 0;
+ * Set this bit to clear the i2s_in_dscr_err_int interrupt
+ */
+
+#define I2S_IN_DSCR_ERR_INT_CLR    (BIT(13))
+#define I2S_IN_DSCR_ERR_INT_CLR_M  (I2S_IN_DSCR_ERR_INT_CLR_V << 
I2S_IN_DSCR_ERR_INT_CLR_S)
+#define I2S_IN_DSCR_ERR_INT_CLR_V  0x00000001
+#define I2S_IN_DSCR_ERR_INT_CLR_S  13
+
+/* I2S_OUT_EOF_INT_CLR : WO; bitpos: [12]; default: 0;
+ * Set this bit to clear the i2s_out_eof_int interrupt
+ */
+
+#define I2S_OUT_EOF_INT_CLR    (BIT(12))
+#define I2S_OUT_EOF_INT_CLR_M  (I2S_OUT_EOF_INT_CLR_V << I2S_OUT_EOF_INT_CLR_S)
+#define I2S_OUT_EOF_INT_CLR_V  0x00000001
+#define I2S_OUT_EOF_INT_CLR_S  12
+
+/* I2S_OUT_DONE_INT_CLR : WO; bitpos: [11]; default: 0;
+ * Set this bit to clear the i2s_out_done_int interrupt
+ */
+
+#define I2S_OUT_DONE_INT_CLR    (BIT(11))
+#define I2S_OUT_DONE_INT_CLR_M  (I2S_OUT_DONE_INT_CLR_V << 
I2S_OUT_DONE_INT_CLR_S)
+#define I2S_OUT_DONE_INT_CLR_V  0x00000001
+#define I2S_OUT_DONE_INT_CLR_S  11
+
+/* I2S_IN_ERR_EOF_INT_CLR : WO; bitpos: [10]; default: 0;
+ * don't use
+ */
+
+#define I2S_IN_ERR_EOF_INT_CLR    (BIT(10))
+#define I2S_IN_ERR_EOF_INT_CLR_M  (I2S_IN_ERR_EOF_INT_CLR_V << 
I2S_IN_ERR_EOF_INT_CLR_S)
+#define I2S_IN_ERR_EOF_INT_CLR_V  0x00000001
+#define I2S_IN_ERR_EOF_INT_CLR_S  10
+
+/* I2S_IN_SUC_EOF_INT_CLR : WO; bitpos: [9]; default: 0;
+ * Set this bit to clear the i2s_in_suc_eof_int interrupt
+ */
+
+#define I2S_IN_SUC_EOF_INT_CLR    (BIT(9))
+#define I2S_IN_SUC_EOF_INT_CLR_M  (I2S_IN_SUC_EOF_INT_CLR_V << 
I2S_IN_SUC_EOF_INT_CLR_S)
+#define I2S_IN_SUC_EOF_INT_CLR_V  0x00000001
+#define I2S_IN_SUC_EOF_INT_CLR_S  9
+
+/* I2S_IN_DONE_INT_CLR : WO; bitpos: [8]; default: 0;
+ * Set this bit to clear the i2s_in_done_int interrupt
+ */
+
+#define I2S_IN_DONE_INT_CLR    (BIT(8))
+#define I2S_IN_DONE_INT_CLR_M  (I2S_IN_DONE_INT_CLR_V << I2S_IN_DONE_INT_CLR_S)
+#define I2S_IN_DONE_INT_CLR_V  0x00000001
+#define I2S_IN_DONE_INT_CLR_S  8
+
+/* I2S_TX_HUNG_INT_CLR : WO; bitpos: [7]; default: 0;
+ * Set this bit to clear the i2s_tx_hung_int interrupt
+ */
+
+#define I2S_TX_HUNG_INT_CLR    (BIT(7))
+#define I2S_TX_HUNG_INT_CLR_M  (I2S_TX_HUNG_INT_CLR_V << I2S_TX_HUNG_INT_CLR_S)
+#define I2S_TX_HUNG_INT_CLR_V  0x00000001
+#define I2S_TX_HUNG_INT_CLR_S  7
+
+/* I2S_RX_HUNG_INT_CLR : WO; bitpos: [6]; default: 0;
+ * Set this bit to clear the i2s_rx_hung_int interrupt
+ */
+
+#define I2S_RX_HUNG_INT_CLR    (BIT(6))
+#define I2S_RX_HUNG_INT_CLR_M  (I2S_RX_HUNG_INT_CLR_V << I2S_RX_HUNG_INT_CLR_S)
+#define I2S_RX_HUNG_INT_CLR_V  0x00000001
+#define I2S_RX_HUNG_INT_CLR_S  6
+
+/* I2S_TX_REMPTY_INT_CLR : WO; bitpos: [5]; default: 0;
+ * Set this bit to clear the i2s_tx_rempty_int interrupt
+ */
+
+#define I2S_TX_REMPTY_INT_CLR    (BIT(5))
+#define I2S_TX_REMPTY_INT_CLR_M  (I2S_TX_REMPTY_INT_CLR_V << 
I2S_TX_REMPTY_INT_CLR_S)
+#define I2S_TX_REMPTY_INT_CLR_V  0x00000001
+#define I2S_TX_REMPTY_INT_CLR_S  5
+
+/* I2S_TX_WFULL_INT_CLR : WO; bitpos: [4]; default: 0;
+ * Set this bit to clear the i2s_tx_wfull_int interrupt
+ */
+
+#define I2S_TX_WFULL_INT_CLR    (BIT(4))
+#define I2S_TX_WFULL_INT_CLR_M  (I2S_TX_WFULL_INT_CLR_V << 
I2S_TX_WFULL_INT_CLR_S)
+#define I2S_TX_WFULL_INT_CLR_V  0x00000001
+#define I2S_TX_WFULL_INT_CLR_S  4
+
+/* I2S_RX_REMPTY_INT_CLR : WO; bitpos: [3]; default: 0;
+ * Set this bit to clear the i2s_rx_rempty_int interrupt
+ */
+
+#define I2S_RX_REMPTY_INT_CLR    (BIT(3))
+#define I2S_RX_REMPTY_INT_CLR_M  (I2S_RX_REMPTY_INT_CLR_V << 
I2S_RX_REMPTY_INT_CLR_S)
+#define I2S_RX_REMPTY_INT_CLR_V  0x00000001
+#define I2S_RX_REMPTY_INT_CLR_S  3
+
+/* I2S_RX_WFULL_INT_CLR : WO; bitpos: [2]; default: 0;
+ * Set this bit to clear the i2s_rx_wfull_int interrupt
+ */
+
+#define I2S_RX_WFULL_INT_CLR    (BIT(2))
+#define I2S_RX_WFULL_INT_CLR_M  (I2S_RX_WFULL_INT_CLR_V << 
I2S_RX_WFULL_INT_CLR_S)
+#define I2S_RX_WFULL_INT_CLR_V  0x00000001
+#define I2S_RX_WFULL_INT_CLR_S  2
+
+/* I2S_TX_PUT_DATA_INT_CLR : WO; bitpos: [1]; default: 0;
+ * Set this bit to clear the i2s_tx_put_data_int interrupt
+ */
+
+#define I2S_TX_PUT_DATA_INT_CLR     (BIT(1))
+#define I2S_TX_PUT_DATA_INT_CLR_M   (I2S_TX_PUT_DATA_INT_CLR_V << 
I2S_TX_PUT_DATA_INT_CLR_S)
+#define I2S_TX_PUT_DATA_INT_CLR_V   0x00000001
+#define I2S_TX_PUT_DATA_INT_CLR_S   1
+
+/* I2S_RX_TAKE_DATA_INT_CLR : WO; bitpos: [0]; default: 0;
+ * Set this bit to clear the i2s_rx_take_data_int interrupt
+ */
+
+#define I2S_RX_TAKE_DATA_INT_CLR    (BIT(0))
+#define I2S_RX_TAKE_DATA_INT_CLR_M  (I2S_RX_TAKE_DATA_INT_CLR_V << 
I2S_RX_TAKE_DATA_INT_CLR_S)
+#define I2S_RX_TAKE_DATA_INT_CLR_V  0x00000001
+#define I2S_RX_TAKE_DATA_INT_CLR_S  0
+
+/* I2S_TIMING_REG register
+ * I2S timing register
+ */
+
+#define I2S_TIMING_REG(i) (REG_I2S_BASE(i) + 0x1c)
+
+/* I2S_TX_BCK_IN_INV : R/W; bitpos: [24]; default: 0;
+ * Set this bit to invert BCK signal input to the slave transmitter
+ */
+
+#define I2S_TX_BCK_IN_INV    (BIT(24))
+#define I2S_TX_BCK_IN_INV_M  (I2S_TX_BCK_IN_INV_V << I2S_TX_BCK_IN_INV_S)
+#define I2S_TX_BCK_IN_INV_V  0x00000001
+#define I2S_TX_BCK_IN_INV_S  24
+
+/* I2S_DATA_ENABLE_DELAY : R/W; bitpos: [23:22]; default: 0;
+ * Number of delay cycles for data valid flag.
+ */
+
+#define I2S_DATA_ENABLE_DELAY    0x00000003
+#define I2S_DATA_ENABLE_DELAY_M  (I2S_DATA_ENABLE_DELAY_V << 
I2S_DATA_ENABLE_DELAY_S)
+#define I2S_DATA_ENABLE_DELAY_V  0x00000003
+#define I2S_DATA_ENABLE_DELAY_S  22
+
+/* I2S_RX_DSYNC_SW : R/W; bitpos: [21]; default: 0;
+ * Set this bit to synchronize signals with the double sync method into the
+ * receiver
+ */
+
+#define I2S_RX_DSYNC_SW    (BIT(21))
+#define I2S_RX_DSYNC_SW_M  (I2S_RX_DSYNC_SW_V << I2S_RX_DSYNC_SW_S)
+#define I2S_RX_DSYNC_SW_V  0x00000001
+#define I2S_RX_DSYNC_SW_S  21
+
+/* I2S_TX_DSYNC_SW : R/W; bitpos: [20]; default: 0;
+ * Set this bit to synchronize signals with the double sync method into the
+ * transmitter
+ */
+
+#define I2S_TX_DSYNC_SW    (BIT(20))
+#define I2S_TX_DSYNC_SW_M  (I2S_TX_DSYNC_SW_V << I2S_TX_DSYNC_SW_S)
+#define I2S_TX_DSYNC_SW_V  0x00000001
+#define I2S_TX_DSYNC_SW_S  20
+
+/* I2S_RX_BCK_OUT_DELAY : R/W; bitpos: [19:18]; default: 0;
+ * Number of delay cycles for BCK out of the receiver
+ */
+
+#define I2S_RX_BCK_OUT_DELAY    0x00000003
+#define I2S_RX_BCK_OUT_DELAY_M  (I2S_RX_BCK_OUT_DELAY_V << 
I2S_RX_BCK_OUT_DELAY_S)
+#define I2S_RX_BCK_OUT_DELAY_V  0x00000003
+#define I2S_RX_BCK_OUT_DELAY_S  18
+
+/* I2S_RX_WS_OUT_DELAY : R/W; bitpos: [17:16]; default: 0;
+ * Number of delay cycles for WS out of the receiver
+ */
+
+#define I2S_RX_WS_OUT_DELAY    0x00000003
+#define I2S_RX_WS_OUT_DELAY_M  (I2S_RX_WS_OUT_DELAY_V << I2S_RX_WS_OUT_DELAY_S)
+#define I2S_RX_WS_OUT_DELAY_V  0x00000003
+#define I2S_RX_WS_OUT_DELAY_S  16
+
+/* I2S_TX_SD_OUT_DELAY : R/W; bitpos: [15:14]; default: 0;
+ * Number of delay cycles for SD out of the transmitter
+ */
+
+#define I2S_TX_SD_OUT_DELAY    0x00000003
+#define I2S_TX_SD_OUT_DELAY_M  (I2S_TX_SD_OUT_DELAY_V << I2S_TX_SD_OUT_DELAY_S)
+#define I2S_TX_SD_OUT_DELAY_V  0x00000003
+#define I2S_TX_SD_OUT_DELAY_S  14
+
+/* I2S_TX_WS_OUT_DELAY : R/W; bitpos: [13:12]; default: 0;
+ * Number of delay cycles for WS out of the transmitter
+ */
+
+#define I2S_TX_WS_OUT_DELAY    0x00000003
+#define I2S_TX_WS_OUT_DELAY_M  (I2S_TX_WS_OUT_DELAY_V << I2S_TX_WS_OUT_DELAY_S)
+#define I2S_TX_WS_OUT_DELAY_V  0x00000003
+#define I2S_TX_WS_OUT_DELAY_S  12
+
+/* I2S_TX_BCK_OUT_DELAY : R/W; bitpos: [11:10]; default: 0;
+ * Number of delay cycles for BCK out of the transmitter
+ */
+
+#define I2S_TX_BCK_OUT_DELAY    0x00000003
+#define I2S_TX_BCK_OUT_DELAY_M  (I2S_TX_BCK_OUT_DELAY_V << 
I2S_TX_BCK_OUT_DELAY_S)
+#define I2S_TX_BCK_OUT_DELAY_V  0x00000003
+#define I2S_TX_BCK_OUT_DELAY_S  10
+
+/* I2S_RX_SD_IN_DELAY : R/W; bitpos: [9:8]; default: 0;
+ * Number of delay cycles for SD into the receiver
+ */
+
+#define I2S_RX_SD_IN_DELAY    0x00000003
+#define I2S_RX_SD_IN_DELAY_M  (I2S_RX_SD_IN_DELAY_V << I2S_RX_SD_IN_DELAY_S)
+#define I2S_RX_SD_IN_DELAY_V  0x00000003
+#define I2S_RX_SD_IN_DELAY_S  8
+
+/* I2S_RX_WS_IN_DELAY : R/W; bitpos: [7:6]; default: 0;
+ * Number of delay cycles for WS into the receiver
+ */
+
+#define I2S_RX_WS_IN_DELAY    0x00000003
+#define I2S_RX_WS_IN_DELAY_M  (I2S_RX_WS_IN_DELAY_V << I2S_RX_WS_IN_DELAY_S)
+#define I2S_RX_WS_IN_DELAY_V  0x00000003
+#define I2S_RX_WS_IN_DELAY_S  6
+
+/* I2S_RX_BCK_IN_DELAY : R/W; bitpos: [5:4]; default: 0;
+ * Number of delay cycles for BCK into the receiver
+ */
+
+#define I2S_RX_BCK_IN_DELAY    0x00000003
+#define I2S_RX_BCK_IN_DELAY_M  (I2S_RX_BCK_IN_DELAY_V << I2S_RX_BCK_IN_DELAY_S)
+#define I2S_RX_BCK_IN_DELAY_V  0x00000003
+#define I2S_RX_BCK_IN_DELAY_S  4
+
+/* I2S_TX_WS_IN_DELAY : R/W; bitpos: [3:2]; default: 0;
+ * Number of delay cycles for WS into the transmitter
+ */
+
+#define I2S_TX_WS_IN_DELAY    0x00000003
+#define I2S_TX_WS_IN_DELAY_M  (I2S_TX_WS_IN_DELAY_V << I2S_TX_WS_IN_DELAY_S)
+#define I2S_TX_WS_IN_DELAY_V  0x00000003
+#define I2S_TX_WS_IN_DELAY_S  2
+
+/* I2S_TX_BCK_IN_DELAY : R/W; bitpos: [1:0]; default: 0;
+ * Number of delay cycles for BCK into the transmitter
+ */
+
+#define I2S_TX_BCK_IN_DELAY    0x00000003
+#define I2S_TX_BCK_IN_DELAY_M  (I2S_TX_BCK_IN_DELAY_V << I2S_TX_BCK_IN_DELAY_S)
+#define I2S_TX_BCK_IN_DELAY_V  0x00000003
+#define I2S_TX_BCK_IN_DELAY_S  0
+
+/* I2S_FIFO_CONF_REG register
+ * I2S FIFO configure register
+ */
+
+#define I2S_FIFO_CONF_REG(i) (REG_I2S_BASE(i) + 0x20)
+
+/* I2S_RX_FIFO_MOD_FORCE_EN : R/W; bitpos: [20]; default: 0;
+ * The bit should always be set to 1
+ */
+
+#define I2S_RX_FIFO_MOD_FORCE_EN    (BIT(20))
+#define I2S_RX_FIFO_MOD_FORCE_EN_M  (I2S_RX_FIFO_MOD_FORCE_EN_V << 
I2S_RX_FIFO_MOD_FORCE_EN_S)
+#define I2S_RX_FIFO_MOD_FORCE_EN_V  0x00000001
+#define I2S_RX_FIFO_MOD_FORCE_EN_S  20
+
+/* I2S_TX_FIFO_MOD_FORCE_EN : R/W; bitpos: [19]; default: 0;
+ * The bit should always be set to 1
+ */
+
+#define I2S_TX_FIFO_MOD_FORCE_EN    (BIT(19))
+#define I2S_TX_FIFO_MOD_FORCE_EN_M  (I2S_TX_FIFO_MOD_FORCE_EN_V << 
I2S_TX_FIFO_MOD_FORCE_EN_S)
+#define I2S_TX_FIFO_MOD_FORCE_EN_V  0x00000001
+#define I2S_TX_FIFO_MOD_FORCE_EN_S  19
+
+/* I2S_RX_FIFO_MOD : R/W; bitpos: [18:16]; default: 0;
+ * Receiver FIFO mode configuration bits
+ */
+
+#define I2S_RX_FIFO_MOD    0x00000007
+#define I2S_RX_FIFO_MOD_M  (I2S_RX_FIFO_MOD_V << I2S_RX_FIFO_MOD_S)
+#define I2S_RX_FIFO_MOD_V  0x00000007
+#define I2S_RX_FIFO_MOD_S  16
+
+/* I2S_TX_FIFO_MOD : R/W; bitpos: [15:13]; default: 0;
+ * Transmitter FIFO mode configuration bits
+ */
+
+#define I2S_TX_FIFO_MOD    0x00000007
+#define I2S_TX_FIFO_MOD_M  (I2S_TX_FIFO_MOD_V << I2S_TX_FIFO_MOD_S)
+#define I2S_TX_FIFO_MOD_V  0x00000007
+#define I2S_TX_FIFO_MOD_S  13
+
+/* I2S_DSCR_EN : R/W; bitpos: [12]; default: 1;
+ * Set this bit to enable I2S DMA mode
+ */
+
+#define I2S_DSCR_EN    (BIT(12))
+#define I2S_DSCR_EN_M  (I2S_DSCR_EN_V << I2S_DSCR_EN_S)
+#define I2S_DSCR_EN_V  0x00000001
+#define I2S_DSCR_EN_S  12
+
+/* I2S_TX_DATA_NUM : R/W; bitpos: [11:6]; default: 32;
+ * Threshold of data length in transmitter FIFO
+ */
+
+#define I2S_TX_DATA_NUM    0x0000003F
+#define I2S_TX_DATA_NUM_M  (I2S_TX_DATA_NUM_V << I2S_TX_DATA_NUM_S)
+#define I2S_TX_DATA_NUM_V  0x0000003F
+#define I2S_TX_DATA_NUM_S  6
 
-#include "esp32_soc.h"
+/* I2S_RX_DATA_NUM : R/W; bitpos: [5:0]; default: 32;
+ * Threshold of data length in receiver FIFO
+ */
 
-#define REG_I2S_BASE( i )       (DR_REG_I2S_BASE + ((i)*0x1e000))
-#define I2S_PD_CONF_REG(i)      (REG_I2S_BASE(i) + 0x00a4)
+#define I2S_RX_DATA_NUM    0x0000003F
+#define I2S_RX_DATA_NUM_M  (I2S_RX_DATA_NUM_V << I2S_RX_DATA_NUM_S)
+#define I2S_RX_DATA_NUM_V  0x0000003F
+#define I2S_RX_DATA_NUM_S  0
 
-/* I2S_PLC_MEM_FORCE_PU : R/W ;bitpos:[3] ;default: 1'h1 ; */
+/* I2S_RXEOF_NUM_REG register
+ * I2S DMA RX EOF data length
+ */
+
+#define I2S_RXEOF_NUM_REG(i) (REG_I2S_BASE(i) + 0x24)
+
+/* I2S_RX_EOF_NUM : R/W; bitpos: [31:0]; default: 64;
+ * the length of data to be received. It will trigger i2s_in_suc_eof_int.
+ */
+
+#define I2S_RX_EOF_NUM    0xFFFFFFFF
+#define I2S_RX_EOF_NUM_M  (I2S_RX_EOF_NUM_V << I2S_RX_EOF_NUM_S)
+#define I2S_RX_EOF_NUM_V  0xFFFFFFFF
+#define I2S_RX_EOF_NUM_S  0
+
+/* I2S_CONF_SIGLE_DATA_REG register
+ * Constant single channel data
+ */
+
+#define I2S_CONF_SINGLE_DATA_REG(i) (REG_I2S_BASE(i) + 0x28)
+
+/* I2S_SIGLE_DATA : R/W; bitpos: [31:0]; default: 0;
+ * the right channel or left channel put out constant value stored in this
+ * register according to tx_chan_mod and reg_tx_msb_right
+ */
+
+#define I2S_SIGLE_DATA    0xFFFFFFFF
+#define I2S_SIGLE_DATA_M  (I2S_SIGLE_DATA_V << I2S_SIGLE_DATA_S)
+#define I2S_SIGLE_DATA_V  0xFFFFFFFF
+#define I2S_SIGLE_DATA_S  0
+
+/* I2S_CONF_CHAN_REG register
+ * I2S channel configure register
+ */
+
+#define I2S_CONF_CHAN_REG(i) (REG_I2S_BASE(i) + 0x2c)
+
+/* I2S_RX_CHAN_MOD : R/W; bitpos: [4:3]; default: 0;
+ * I2S receiver channel mode configuration bits.
+ */
+
+#define I2S_RX_CHAN_MOD    0x00000003
+#define I2S_RX_CHAN_MOD_M  (I2S_RX_CHAN_MOD_V << I2S_RX_CHAN_MOD_S)
+#define I2S_RX_CHAN_MOD_V  0x00000003
+#define I2S_RX_CHAN_MOD_S  3
+
+/* I2S_TX_CHAN_MOD : R/W; bitpos: [2:0]; default: 0;
+ * 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  0x00000007
+#define I2S_TX_CHAN_MOD_S  0
+
+/* I2S_OUT_LINK_REG register
+ * I2S DMA TX configure register
+ */
+
+#define I2S_OUT_LINK_REG(i) (REG_I2S_BASE(i) + 0x30)
+
+/* I2S_OUTLINK_RESTART : R/W; bitpos: [30]; default: 0;
+ * Set this bit to restart outlink descriptor
+ */
+
+#define I2S_OUTLINK_RESTART    (BIT(30))
+#define I2S_OUTLINK_RESTART_M  (I2S_OUTLINK_RESTART_V << I2S_OUTLINK_RESTART_S)
+#define I2S_OUTLINK_RESTART_V  0x00000001
+#define I2S_OUTLINK_RESTART_S  30
+
+/* I2S_OUTLINK_START : R/W; bitpos: [29]; default: 0;
+ * Set this bit to start outlink descriptor
+ */
+
+#define I2S_OUTLINK_START    (BIT(29))
+#define I2S_OUTLINK_START_M  (I2S_OUTLINK_START_V << I2S_OUTLINK_START_S)
+#define I2S_OUTLINK_START_V  0x00000001
+#define I2S_OUTLINK_START_S  29
+
+/* I2S_OUTLINK_STOP : R/W; bitpos: [28]; default: 0;
+ * Set this bit to stop outlink descriptor
+ */
+
+#define I2S_OUTLINK_STOP    (BIT(28))
+#define I2S_OUTLINK_STOP_M  (I2S_OUTLINK_STOP_V << I2S_OUTLINK_STOP_S)
+#define I2S_OUTLINK_STOP_V  0x00000001
+#define I2S_OUTLINK_STOP_S  28
+
+/* I2S_OUTLINK_ADDR : R/W; bitpos: [19:0]; default: 0;
+ * The address of first outlink descriptor
+ */
+
+#define I2S_OUTLINK_ADDR    0x000FFFFF
+#define I2S_OUTLINK_ADDR_M  (I2S_OUTLINK_ADDR_V << I2S_OUTLINK_ADDR_S)
+#define I2S_OUTLINK_ADDR_V  0x000FFFFF
+#define I2S_OUTLINK_ADDR_S  0
+
+/* I2S_IN_LINK_REG register
+ * I2S DMA RX configure register
+ */
+
+#define I2S_IN_LINK_REG(i) (REG_I2S_BASE(i) + 0x34)
+
+/* I2S_INLINK_RESTART : R/W; bitpos: [30]; default: 0;
+ * Set this bit to restart inlink descriptor
+ */
+
+#define I2S_INLINK_RESTART    (BIT(30))
+#define I2S_INLINK_RESTART_M  (I2S_INLINK_RESTART_V << I2S_INLINK_RESTART_S)
+#define I2S_INLINK_RESTART_V  0x00000001
+#define I2S_INLINK_RESTART_S  30
+
+/* I2S_INLINK_START : R/W; bitpos: [29]; default: 0;
+ * Set this bit to start inlink descriptor
+ */
+
+#define I2S_INLINK_START    (BIT(29))
+#define I2S_INLINK_START_M  (I2S_INLINK_START_V << I2S_INLINK_START_S)
+#define I2S_INLINK_START_V  0x00000001
+#define I2S_INLINK_START_S  29
+
+/* I2S_INLINK_STOP : R/W; bitpos: [28]; default: 0;
+ * Set this bit to stop inlink descriptor
+ */
+
+#define I2S_INLINK_STOP    (BIT(28))
+#define I2S_INLINK_STOP_M  (I2S_INLINK_STOP_V << I2S_INLINK_STOP_S)
+#define I2S_INLINK_STOP_V  0x00000001
+#define I2S_INLINK_STOP_S  28
+
+/* I2S_INLINK_ADDR : R/W; bitpos: [19:0]; default: 0;
+ * The address of first inlink descriptor
+ */
+
+#define I2S_INLINK_ADDR    0x000FFFFF
+#define I2S_INLINK_ADDR_M  (I2S_INLINK_ADDR_V << I2S_INLINK_ADDR_S)
+#define I2S_INLINK_ADDR_V  0x000FFFFF
+#define I2S_INLINK_ADDR_S  0
+
+/* I2S_OUT_EOF_DES_ADDR_REG register
+ * The address of outlink descriptor that produces EOF
+ */
+
+#define I2S_OUT_EOF_DES_ADDR_REG(i) (REG_I2S_BASE(i) + 0x38)
+
+/* I2S_OUT_EOF_DES_ADDR : RO; bitpos: [31:0]; default: 0;
+ * The address of outlink descriptor that produces EOF
+ */
+
+#define I2S_OUT_EOF_DES_ADDR    0xFFFFFFFF
+#define I2S_OUT_EOF_DES_ADDR_M  (I2S_OUT_EOF_DES_ADDR_V << 
I2S_OUT_EOF_DES_ADDR_S)
+#define I2S_OUT_EOF_DES_ADDR_V  0xFFFFFFFF
+#define I2S_OUT_EOF_DES_ADDR_S  0
+
+/* I2S_IN_EOF_DES_ADDR_REG register
+ * The address of inlink descriptor that produces EOF
+ */
+
+#define I2S_IN_EOF_DES_ADDR_REG(i) (REG_I2S_BASE(i) + 0x3c)
+
+/* I2S_IN_EOF_DES_ADDR_REG : RO; bitpos: [31:0]; default: 0;
+ * The address of inlink descriptor that produces EOF
+ */
+
+#define I2S_IN_EOF_DES_ADDR     0xFFFFFFFF
+#define I2S_IN_EOF_DES_ADDR_M   (I2S_IN_EOF_DES_ADDR_V << 
I2S_IN_EOF_DES_ADDR_S)
+#define I2S_IN_EOF_DES_ADDR_V   0xFFFFFFFF
+#define I2S_IN_EOF_DES_ADDR_S   0
+
+/* I2S_OUT_EOF_BFR_DES_ADDR_REG register
+ * The address of buffer relative to the outlink descriptor that produces EOF
+ */
+
+#define I2S_OUT_EOF_BFR_DES_ADDR_REG(i) (REG_I2S_BASE(i) + 0x40)
+
+/* I2S_OUT_EOF_BFR_DES_ADDR : RO; bitpos: [31:0]; default: 0;
+ * The address of buffer relative to the outlink descriptor that produces EOF
+ */
+
+#define I2S_OUT_EOF_BFR_DES_ADDR    0xFFFFFFFF
+#define I2S_OUT_EOF_BFR_DES_ADDR_M  (I2S_OUT_EOF_BFR_DES_ADDR_V << 
I2S_OUT_EOF_BFR_DES_ADDR_S)
+#define I2S_OUT_EOF_BFR_DES_ADDR_V  0xFFFFFFFF
+#define I2S_OUT_EOF_BFR_DES_ADDR_S  0
+
+/* I2S_INLINK_DSCR_REG register
+ * The address of current inlink descriptor
+ */
+
+#define I2S_INLINK_DSCR_REG(i) (REG_I2S_BASE(i) + 0x48)
+
+/* I2S_INLINK_DSCR : RO; bitpos: [31:0]; default: 0;
+ * The address of current inlink descriptor
+ */
+
+#define I2S_INLINK_DSCR    0xFFFFFFFF
+#define I2S_INLINK_DSCR_M  (I2S_INLINK_DSCR_V << I2S_INLINK_DSCR_S)
+#define I2S_INLINK_DSCR_V  0xFFFFFFFF
+#define I2S_INLINK_DSCR_S  0
+
+/* I2S_INLINK_DSCR_BF0_REG register
+ * The address of next inlink descriptor
+ */
+
+#define I2S_INLINK_DSCR_BF0_REG(i) (REG_I2S_BASE(i) + 0x4c)
+
+/* I2S_INLINK_DSCR_BF0 : RO; bitpos: [31:0]; default: 0;
+ * The address of next inlink descriptor
+ */
+
+#define I2S_INLINK_DSCR_BF0    0xFFFFFFFF
+#define I2S_INLINK_DSCR_BF0_M  (I2S_INLINK_DSCR_BF0_V << I2S_INLINK_DSCR_BF0_S)
+#define I2S_INLINK_DSCR_BF0_V  0xFFFFFFFF
+#define I2S_INLINK_DSCR_BF0_S  0
+
+/* I2S_INLINK_DSCR_BF1_REG register
+ * The address of next inlink data buffer
+ */
+
+#define I2S_INLINK_DSCR_BF1_REG(i) (REG_I2S_BASE(i) + 0x50)
+
+/* I2S_INLINK_DSCR_BF1 : RO; bitpos: [31:0]; default: 0;
+ * The address of next inlink data buffer
+ */
+
+#define I2S_INLINK_DSCR_BF1    0xFFFFFFFF
+#define I2S_INLINK_DSCR_BF1_M  (I2S_INLINK_DSCR_BF1_V << I2S_INLINK_DSCR_BF1_S)
+#define I2S_INLINK_DSCR_BF1_V  0xFFFFFFFF
+#define I2S_INLINK_DSCR_BF1_S  0
+
+/* I2S_OUTLINK_DSCR_REG register
+ * The address of current outlink descriptor
+ */
+
+#define I2S_OUTLINK_DSCR_REG(i) (REG_I2S_BASE(i) + 0x54)
+
+/* I2S_OUTLINK_DSCR : RO; bitpos: [31:0]; default: 0;
+ * The address of current outlink descriptor
+ */
+
+#define I2S_OUTLINK_DSCR    0xFFFFFFFF
+#define I2S_OUTLINK_DSCR_M  (I2S_OUTLINK_DSCR_V << I2S_OUTLINK_DSCR_S)
+#define I2S_OUTLINK_DSCR_V  0xFFFFFFFF
+#define I2S_OUTLINK_DSCR_S  0
+
+/* I2S_OUTLINK_DSCR_BF0_REG register
+ * The address of next outlink descriptor
+ */
+
+#define I2S_OUTLINK_DSCR_BF0_REG(i) (REG_I2S_BASE(i) + 0x58)
+
+/* I2S_OUTLINK_DSCR_BF0 : RO; bitpos: [31:0]; default: 0;
+ * The address of next outlink descriptor
+ */
+
+#define I2S_OUTLINK_DSCR_BF0    0xFFFFFFFF
+#define I2S_OUTLINK_DSCR_BF0_M  (I2S_OUTLINK_DSCR_BF0_V << 
I2S_OUTLINK_DSCR_BF0_S)
+#define I2S_OUTLINK_DSCR_BF0_V  0xFFFFFFFF
+#define I2S_OUTLINK_DSCR_BF0_S  0
+
+/* I2S_OUTLINK_DSCR_BF1_REG register
+ * The address of next outlink data buffer
+ */
+
+#define I2S_OUTLINK_DSCR_BF1_REG(i) (REG_I2S_BASE(i) + 0x5c)
+
+/* I2S_OUTLINK_DSCR_BF1 : RO; bitpos: [31:0]; default: 0;
+ * The address of next outlink data buffer
+ */
+
+#define I2S_OUTLINK_DSCR_BF1    0xFFFFFFFF
+#define I2S_OUTLINK_DSCR_BF1_M  (I2S_OUTLINK_DSCR_BF1_V << 
I2S_OUTLINK_DSCR_BF1_S)
+#define I2S_OUTLINK_DSCR_BF1_V  0xFFFFFFFF
+#define I2S_OUTLINK_DSCR_BF1_S  0
+
+/* I2S_LC_CONF_REG register
+ * I2S DMA configuration register
+ */
+
+#define I2S_LC_CONF_REG(i) (REG_I2S_BASE(i) + 0x60)
+
+/* I2S_EXT_MEM_BK_SIZE : R/W; bitpos: [15:14]; default: 0;
+ * DMA access external memory block size. 0: 16 bytes      1: 32 bytes
+ * 2:64 bytes      3:reserved
+ */
+
+#define I2S_EXT_MEM_BK_SIZE    0x00000003
+#define I2S_EXT_MEM_BK_SIZE_M  (I2S_EXT_MEM_BK_SIZE_V << I2S_EXT_MEM_BK_SIZE_S)
+#define I2S_EXT_MEM_BK_SIZE_V  0x00000003
+#define I2S_EXT_MEM_BK_SIZE_S  14
+
+/* I2S_MEM_TRANS_EN : R/W; bitpos: [13]; default: 0;
+ * don't use
+ */
+
+#define I2S_MEM_TRANS_EN    (BIT(13))
+#define I2S_MEM_TRANS_EN_M  (I2S_MEM_TRANS_EN_V << I2S_MEM_TRANS_EN_S)
+#define I2S_MEM_TRANS_EN_V  0x00000001
+#define I2S_MEM_TRANS_EN_S  13
+
+/* I2S_CHECK_OWNER : R/W; bitpos: [12]; default: 0;
+ * Set this bit to enable check owner bit by hardware
+ */
+
+#define I2S_CHECK_OWNER    (BIT(12))
+#define I2S_CHECK_OWNER_M  (I2S_CHECK_OWNER_V << I2S_CHECK_OWNER_S)
+#define I2S_CHECK_OWNER_V  0x00000001
+#define I2S_CHECK_OWNER_S  12
+
+/* I2S_OUT_DATA_BURST_EN : R/W; bitpos: [11]; default: 0;
+ * Transmitter data transfer mode configuration bit. 1:  to prepare out data
+ * with burst mode      0: to prepare out data with byte mode
+ */
+
+#define I2S_OUT_DATA_BURST_EN    (BIT(11))
+#define I2S_OUT_DATA_BURST_EN_M  (I2S_OUT_DATA_BURST_EN_V << 
I2S_OUT_DATA_BURST_EN_S)
+#define I2S_OUT_DATA_BURST_EN_V  0x00000001
+#define I2S_OUT_DATA_BURST_EN_S  11
+
+/* I2S_INDSCR_BURST_EN : R/W; bitpos: [10]; default: 0;
+ * DMA inlink descriptor transfer mode configuration bit. 1:  to prepare
+ * inlink descriptor with burst mode    0: to prepare inlink descriptor with
+ * byte mode
+ */
+
+#define I2S_INDSCR_BURST_EN    (BIT(10))
+#define I2S_INDSCR_BURST_EN_M  (I2S_INDSCR_BURST_EN_V << I2S_INDSCR_BURST_EN_S)
+#define I2S_INDSCR_BURST_EN_V  0x00000001
+#define I2S_INDSCR_BURST_EN_S  10
+
+/* I2S_OUTDSCR_BURST_EN : R/W; bitpos: [9]; default: 0;
+ * DMA outlink descriptor transfer mode configuration bit. 1:  to prepare
+ * outlink descriptor with burst mode    0: to prepare outlink descriptor
+ * with byte mode
+ */
+
+#define I2S_OUTDSCR_BURST_EN    (BIT(9))
+#define I2S_OUTDSCR_BURST_EN_M  (I2S_OUTDSCR_BURST_EN_V << 
I2S_OUTDSCR_BURST_EN_S)
+#define I2S_OUTDSCR_BURST_EN_V  0x00000001
+#define I2S_OUTDSCR_BURST_EN_S  9
+
+/* I2S_OUT_EOF_MODE : R/W; bitpos: [8]; default: 1;
+ * DMA out EOF flag generation mode . 1: when dma has popped all data from
+ * the FIFO  0:when ahb has pushed all data to the FIFO
+ */
+
+#define I2S_OUT_EOF_MODE    (BIT(8))
+#define I2S_OUT_EOF_MODE_M  (I2S_OUT_EOF_MODE_V << I2S_OUT_EOF_MODE_S)
+#define I2S_OUT_EOF_MODE_V  0x00000001
+#define I2S_OUT_EOF_MODE_S  8
+
+/* I2S_OUT_NO_RESTART_CLR : R/W; bitpos: [7]; default: 0;
+ * don't use
+ */
+
+#define I2S_OUT_NO_RESTART_CLR    (BIT(7))
+#define I2S_OUT_NO_RESTART_CLR_M  (I2S_OUT_NO_RESTART_CLR_V << 
I2S_OUT_NO_RESTART_CLR_S)
+#define I2S_OUT_NO_RESTART_CLR_V  0x00000001
+#define I2S_OUT_NO_RESTART_CLR_S  7
+
+/* I2S_OUT_AUTO_WRBACK : R/W; bitpos: [6]; default: 0;
+ * Set this bit to enable outlink-written-back automatically when out buffer
+ * is transmitted done.
+ */
+
+#define I2S_OUT_AUTO_WRBACK    (BIT(6))
+#define I2S_OUT_AUTO_WRBACK_M  (I2S_OUT_AUTO_WRBACK_V << I2S_OUT_AUTO_WRBACK_S)
+#define I2S_OUT_AUTO_WRBACK_V  0x00000001
+#define I2S_OUT_AUTO_WRBACK_S  6
+
+/* I2S_OUT_LOOP_TEST : R/W; bitpos: [5]; default: 0;
+ * Set this bit to loop test outlink
+ */
+
+#define I2S_OUT_LOOP_TEST    (BIT(5))
+#define I2S_OUT_LOOP_TEST_M  (I2S_OUT_LOOP_TEST_V << I2S_OUT_LOOP_TEST_S)
+#define I2S_OUT_LOOP_TEST_V  0x00000001
+#define I2S_OUT_LOOP_TEST_S  5
+
+/* I2S_IN_LOOP_TEST : R/W; bitpos: [4]; default: 0;
+ * Set this bit to loop test inlink
+ */
+
+#define I2S_IN_LOOP_TEST    (BIT(4))
+#define I2S_IN_LOOP_TEST_M  (I2S_IN_LOOP_TEST_V << I2S_IN_LOOP_TEST_S)
+#define I2S_IN_LOOP_TEST_V  0x00000001
+#define I2S_IN_LOOP_TEST_S  4
+
+/* I2S_AHBM_RST : R/W; bitpos: [3]; default: 0;
+ * Set this bit to reset ahb interface of DMA
+ */
+
+#define I2S_AHBM_RST    (BIT(3))
+#define I2S_AHBM_RST_M  (I2S_AHBM_RST_V << I2S_AHBM_RST_S)
+#define I2S_AHBM_RST_V  0x00000001
+#define I2S_AHBM_RST_S  3
+
+/* I2S_AHBM_FIFO_RST : R/W; bitpos: [2]; default: 0;
+ * Set this bit to reset ahb interface cmdFIFO of DMA
+ */
+
+#define I2S_AHBM_FIFO_RST    (BIT(2))
+#define I2S_AHBM_FIFO_RST_M  (I2S_AHBM_FIFO_RST_V << I2S_AHBM_FIFO_RST_S)
+#define I2S_AHBM_FIFO_RST_V  0x00000001
+#define I2S_AHBM_FIFO_RST_S  2
+
+/* I2S_OUT_RST : R/W; bitpos: [1]; default: 0;
+ * Set this bit to reset out dma FSM
+ */
+
+#define I2S_OUT_RST    (BIT(1))
+#define I2S_OUT_RST_M  (I2S_OUT_RST_V << I2S_OUT_RST_S)
+#define I2S_OUT_RST_V  0x00000001
+#define I2S_OUT_RST_S  1
+
+/* I2S_IN_RST : R/W; bitpos: [0]; default: 0;
+ * Set this bit to reset in dma FSM
+ */
+
+#define I2S_IN_RST    (BIT(0))
+#define I2S_IN_RST_M  (I2S_IN_RST_V << I2S_IN_RST_S)
+#define I2S_IN_RST_V  0x00000001
+#define I2S_IN_RST_S  0
+
+/* I2S_LC_STATE0_REG register
+ * I2S DMA TX status
+ */
+
+#define I2S_LC_STATE0_REG(i) (REG_I2S_BASE(i) + 0x6c)
+
+/* I2S_OUT_EMPTY : RO; bitpos: [31]; default: 0;
+ * I2S DMA outfifo is empty.
+ */
+
+#define I2S_OUT_EMPTY    (BIT(31))
+#define I2S_OUT_EMPTY_M  (I2S_OUT_EMPTY_V << I2S_OUT_EMPTY_S)
+#define I2S_OUT_EMPTY_V  0x00000001
+#define I2S_OUT_EMPTY_S  31
+
+/* I2S_OUT_FULL : RO; bitpos: [30]; default: 0;
+ * I2S DMA outfifo is full.
+ */
+
+#define I2S_OUT_FULL    (BIT(30))
+#define I2S_OUT_FULL_M  (I2S_OUT_FULL_V << I2S_OUT_FULL_S)
+#define I2S_OUT_FULL_V  0x00000001
+#define I2S_OUT_FULL_S  30
+
+/* I2S_OUTFIFO_CNT : RO; bitpos: [29:23]; default: 0;
+ * The remains of I2S DMA outfifo data.
+ */
+
+#define I2S_OUTFIFO_CNT    0x0000007F
+#define I2S_OUTFIFO_CNT_M  (I2S_OUTFIFO_CNT_V << I2S_OUTFIFO_CNT_S)
+#define I2S_OUTFIFO_CNT_V  0x0000007F
+#define I2S_OUTFIFO_CNT_S  23
+
+/* I2S_OUT_STATE : RO; bitpos: [22:20]; default: 0;
+ * I2S DMA out data state.
+ */
+
+#define I2S_OUT_STATE    0x00000007
+#define I2S_OUT_STATE_M  (I2S_OUT_STATE_V << I2S_OUT_STATE_S)
+#define I2S_OUT_STATE_V  0x00000007
+#define I2S_OUT_STATE_S  20
+
+/* I2S_OUT_DSCR_STATE : RO; bitpos: [19:18]; default: 0;
+ * I2S DMA out descriptor state.
+ */
+
+#define I2S_OUT_DSCR_STATE    0x00000003
+#define I2S_OUT_DSCR_STATE_M  (I2S_OUT_DSCR_STATE_V << I2S_OUT_DSCR_STATE_S)
+#define I2S_OUT_DSCR_STATE_V  0x00000003
+#define I2S_OUT_DSCR_STATE_S  18
+
+/* I2S_OUTLINK_DSCR_ADDR : RO; bitpos: [17:0]; default: 0;
+ * I2S DMA out descriptor address.
+ */
+
+#define I2S_OUTLINK_DSCR_ADDR    0x0003FFFF
+#define I2S_OUTLINK_DSCR_ADDR_M  (I2S_OUTLINK_DSCR_ADDR_V << 
I2S_OUTLINK_DSCR_ADDR_S)
+#define I2S_OUTLINK_DSCR_ADDR_V  0x0003FFFF
+#define I2S_OUTLINK_DSCR_ADDR_S  0
+
+/* I2S_LC_STATE1_REG register
+ * I2S DMA RX status
+ */
+
+#define I2S_LC_STATE1_REG(i) (REG_I2S_BASE(i) + 0x70)
+
+/* I2S_IN_EMPTY : RO; bitpos: [31]; default: 0;
+ * I2S DMA infifo is empty.
+ */
+
+#define I2S_IN_EMPTY    (BIT(31))
+#define I2S_IN_EMPTY_M  (I2S_IN_EMPTY_V << I2S_IN_EMPTY_S)
+#define I2S_IN_EMPTY_V  0x00000001
+#define I2S_IN_EMPTY_S  31
+
+/* I2S_IN_FULL : RO; bitpos: [30]; default: 0;
+ * I2S DMA infifo is full.
+ */
+
+#define I2S_IN_FULL    (BIT(30))
+#define I2S_IN_FULL_M  (I2S_IN_FULL_V << I2S_IN_FULL_S)
+#define I2S_IN_FULL_V  0x00000001
+#define I2S_IN_FULL_S  30
+
+/* I2S_INFIFO_CNT_DEBUG : RO; bitpos: [29:23]; default: 0;
+ * The remains of I2S DMA infifo data.
+ */
+
+#define I2S_INFIFO_CNT_DEBUG    0x0000007F
+#define I2S_INFIFO_CNT_DEBUG_M  (I2S_INFIFO_CNT_DEBUG_V << 
I2S_INFIFO_CNT_DEBUG_S)
+#define I2S_INFIFO_CNT_DEBUG_V  0x0000007F
+#define I2S_INFIFO_CNT_DEBUG_S  23
+
+/* I2S_IN_STATE : RO; bitpos: [22:20]; default: 0;
+ * I2S DMA in data state.
+ */
+
+#define I2S_IN_STATE    0x00000007
+#define I2S_IN_STATE_M  (I2S_IN_STATE_V << I2S_IN_STATE_S)
+#define I2S_IN_STATE_V  0x00000007
+#define I2S_IN_STATE_S  20
+
+/* I2S_IN_DSCR_STATE : RO; bitpos: [19:18]; default: 0;
+ * I2S DMA in descriptor state.
+ */
+
+#define I2S_IN_DSCR_STATE    0x00000003
+#define I2S_IN_DSCR_STATE_M  (I2S_IN_DSCR_STATE_V << I2S_IN_DSCR_STATE_S)
+#define I2S_IN_DSCR_STATE_V  0x00000003
+#define I2S_IN_DSCR_STATE_S  18
+
+/* I2S_INLINK_DSCR_ADDR : RO; bitpos: [17:0]; default: 0;
+ * I2S DMA in descriptor address.
+ */
+
+#define I2S_INLINK_DSCR_ADDR    0x0003FFFF
+#define I2S_INLINK_DSCR_ADDR_M  (I2S_INLINK_DSCR_ADDR_V << 
I2S_INLINK_DSCR_ADDR_S)
+#define I2S_INLINK_DSCR_ADDR_V  0x0003FFFF
+#define I2S_INLINK_DSCR_ADDR_S  0
+
+/* I2S_LC_HUNG_CONF_REG register
+ * I2S Hung configure register
+ */
+
+#define I2S_LC_HUNG_CONF_REG(i) (REG_I2S_BASE(i) + 0x74)
+
+/* I2S_LC_FIFO_TIMEOUT_ENA : R/W; bitpos: [11]; default: 1;
+ * The enable bit for FIFO timeout
+ */
+
+#define I2S_LC_FIFO_TIMEOUT_ENA    (BIT(11))
+#define I2S_LC_FIFO_TIMEOUT_ENA_M  (I2S_LC_FIFO_TIMEOUT_ENA_V << 
I2S_LC_FIFO_TIMEOUT_ENA_S)
+#define I2S_LC_FIFO_TIMEOUT_ENA_V  0x00000001
+#define I2S_LC_FIFO_TIMEOUT_ENA_S  11
+
+/* I2S_LC_FIFO_TIMEOUT_SHIFT : R/W; bitpos: [10:8]; default: 0;
+ * 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  0x00000007
+#define I2S_LC_FIFO_TIMEOUT_SHIFT_S  8
+
+/* I2S_LC_FIFO_TIMEOUT : R/W; bitpos: [7:0]; default: 16;
+ * 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  0x000000FF
+#define I2S_LC_FIFO_TIMEOUT_S  0
+
+/* I2S_CONF1_REG register
+ * I2S configure1 register
+ */
+
+#define I2S_CONF1_REG(i) (REG_I2S_BASE(i) + 0xa0)
+
+/* I2S_TX_ZEROS_RM_EN : R/W; bitpos: [9]; default: 0;
+ * don't use
+ */
+
+#define I2S_TX_ZEROS_RM_EN    (BIT(9))
+#define I2S_TX_ZEROS_RM_EN_M  (I2S_TX_ZEROS_RM_EN_V << I2S_TX_ZEROS_RM_EN_S)
+#define I2S_TX_ZEROS_RM_EN_V  0x00000001
+#define I2S_TX_ZEROS_RM_EN_S  9
+
+/* I2S_TX_STOP_EN : R/W; bitpos: [8]; default: 0;
+ * Set this bit to stop disable output BCK signal and WS signal when tx FIFO
+ * is emtpy
+ */
+
+#define I2S_TX_STOP_EN    (BIT(8))
+#define I2S_TX_STOP_EN_M  (I2S_TX_STOP_EN_V << I2S_TX_STOP_EN_S)
+#define I2S_TX_STOP_EN_V  0x00000001
+#define I2S_TX_STOP_EN_S  8
+
+/* I2S_RX_PCM_BYPASS : R/W; bitpos: [7]; default: 1;
+ * Set this bit to bypass Compress/Decompress module for received data.
+ */
+
+#define I2S_RX_PCM_BYPASS    (BIT(7))
+#define I2S_RX_PCM_BYPASS_M  (I2S_RX_PCM_BYPASS_V << I2S_RX_PCM_BYPASS_S)
+#define I2S_RX_PCM_BYPASS_V  0x00000001
+#define I2S_RX_PCM_BYPASS_S  7
+
+/* I2S_RX_PCM_CONF : R/W; bitpos: [6:4]; default: 0;
+ * Compress/Decompress module configuration bits. 0: decompress received
+ * data  1:compress received data
+ */
+
+#define I2S_RX_PCM_CONF    0x00000007
+#define I2S_RX_PCM_CONF_M  (I2S_RX_PCM_CONF_V << I2S_RX_PCM_CONF_S)
+#define I2S_RX_PCM_CONF_V  0x00000007
+#define I2S_RX_PCM_CONF_S  4
+
+/* I2S_TX_PCM_BYPASS : R/W; bitpos: [3]; default: 1;
+ * Set this bit to bypass  Compress/Decompress module for transmitted data.
+ */
+
+#define I2S_TX_PCM_BYPASS    (BIT(3))
+#define I2S_TX_PCM_BYPASS_M  (I2S_TX_PCM_BYPASS_V << I2S_TX_PCM_BYPASS_S)
+#define I2S_TX_PCM_BYPASS_V  0x00000001
+#define I2S_TX_PCM_BYPASS_S  3
+
+/* I2S_TX_PCM_CONF : R/W; bitpos: [2:0]; default: 1;
+ * Compress/Decompress module configuration bits. 0: decompress transmitted
+ * data  1:compress transmitted data
+ */
+
+#define I2S_TX_PCM_CONF    0x00000007
+#define I2S_TX_PCM_CONF_M  (I2S_TX_PCM_CONF_V << I2S_TX_PCM_CONF_S)
+#define I2S_TX_PCM_CONF_V  0x00000007
+#define I2S_TX_PCM_CONF_S  0
+
+/* I2S_PD_CONF_REG register
+ * I2S power down configure register
+ */
+
+#define I2S_PD_CONF_REG(i) (REG_I2S_BASE(i) + 0xa4)
+
+/* I2S_PLC_MEM_FORCE_PU : R/W; bitpos: [3]; default: 1;
+ * Force I2S memory power-up
+ */
 
 #define I2S_PLC_MEM_FORCE_PU    (BIT(3))
-#define I2S_PLC_MEM_FORCE_PU_M  (BIT(3))
-#define I2S_PLC_MEM_FORCE_PU_V  0x1
+#define I2S_PLC_MEM_FORCE_PU_M  (I2S_PLC_MEM_FORCE_PU_V << 
I2S_PLC_MEM_FORCE_PU_S)
+#define I2S_PLC_MEM_FORCE_PU_V  0x00000001
 #define I2S_PLC_MEM_FORCE_PU_S  3
 
-/* I2S_FIFO_FORCE_PU : R/W ;bitpos:[1] ;default: 1'h1 ; */
+/* I2S_PLC_MEM_FORCE_PD : R/W; bitpos: [2]; default: 0;
+ * Force I2S memory power-down
+ */
+
+#define I2S_PLC_MEM_FORCE_PD    (BIT(2))
+#define I2S_PLC_MEM_FORCE_PD_M  (I2S_PLC_MEM_FORCE_PD_V << 
I2S_PLC_MEM_FORCE_PD_S)
+#define I2S_PLC_MEM_FORCE_PD_V  0x00000001
+#define I2S_PLC_MEM_FORCE_PD_S  2
+
+/* I2S_FIFO_FORCE_PU : R/W; bitpos: [1]; default: 1;
+ * Force FIFO power-up
+ */
+
+#define I2S_FIFO_FORCE_PU    (BIT(1))
+#define I2S_FIFO_FORCE_PU_M  (I2S_FIFO_FORCE_PU_V << I2S_FIFO_FORCE_PU_S)
+#define I2S_FIFO_FORCE_PU_V  0x00000001
+#define I2S_FIFO_FORCE_PU_S  1
+
+/* I2S_FIFO_FORCE_PD : R/W; bitpos: [0]; default: 0;
+ * Force FIFO power-down
+ */
+
+#define I2S_FIFO_FORCE_PD    (BIT(0))
+#define I2S_FIFO_FORCE_PD_M  (I2S_FIFO_FORCE_PD_V << I2S_FIFO_FORCE_PD_S)
+#define I2S_FIFO_FORCE_PD_V  0x00000001
+#define I2S_FIFO_FORCE_PD_S  0
+
+/* I2S_CONF2_REG register
+ * I2S configure2 register
+ */
+
+#define I2S_CONF2_REG(i) (REG_I2S_BASE(i) + 0xa8)
+
+/* I2S_INTER_VALID_EN : R/W; bitpos: [7]; default: 0;
+ * Set this bit to enable camera internal valid
+ */
+
+#define I2S_INTER_VALID_EN    (BIT(7))
+#define I2S_INTER_VALID_EN_M  (I2S_INTER_VALID_EN_V << I2S_INTER_VALID_EN_S)
+#define I2S_INTER_VALID_EN_V  0x00000001
+#define I2S_INTER_VALID_EN_S  7
+
+/* I2S_EXT_ADC_START_EN : R/W; bitpos: [6]; default: 0;
+ * Set this bit to enable the function that ADC mode is triggered by
+ * external signal.
+ */
+
+#define I2S_EXT_ADC_START_EN    (BIT(6))
+#define I2S_EXT_ADC_START_EN_M  (I2S_EXT_ADC_START_EN_V << 
I2S_EXT_ADC_START_EN_S)
+#define I2S_EXT_ADC_START_EN_V  0x00000001
+#define I2S_EXT_ADC_START_EN_S  6
+
+/* I2S_LCD_EN : R/W; bitpos: [5]; default: 0;
+ * Set this bit to enable LCD mode
+ */
+
+#define I2S_LCD_EN    (BIT(5))
+#define I2S_LCD_EN_M  (I2S_LCD_EN_V << I2S_LCD_EN_S)
+#define I2S_LCD_EN_V  0x00000001
+#define I2S_LCD_EN_S  5
+
+/* I2S_LCD_TX_SDX2_EN : R/W; bitpos: [2]; default: 0;
+ * Set this bit to duplicate data pairs (Frame Form 2) in LCD mode.
+ */
+
+#define I2S_LCD_TX_SDX2_EN    (BIT(2))
+#define I2S_LCD_TX_SDX2_EN_M  (I2S_LCD_TX_SDX2_EN_V << I2S_LCD_TX_SDX2_EN_S)
+#define I2S_LCD_TX_SDX2_EN_V  0x00000001
+#define I2S_LCD_TX_SDX2_EN_S  2
+
+/* I2S_LCD_TX_WRX2_EN : R/W; bitpos: [1]; default: 0;
+ * LCD WR double for one datum.
+ */
+
+#define I2S_LCD_TX_WRX2_EN    (BIT(1))
+#define I2S_LCD_TX_WRX2_EN_M  (I2S_LCD_TX_WRX2_EN_V << I2S_LCD_TX_WRX2_EN_S)
+#define I2S_LCD_TX_WRX2_EN_V  0x00000001
+#define I2S_LCD_TX_WRX2_EN_S  1
+
+/* I2S_CAMERA_EN : R/W; bitpos: [0]; default: 0;
+ * Set this bit to enable camera mode
+ */
+
+#define I2S_CAMERA_EN    (BIT(0))
+#define I2S_CAMERA_EN_M  (I2S_CAMERA_EN_V << I2S_CAMERA_EN_S)
+#define I2S_CAMERA_EN_V  0x00000001
+#define I2S_CAMERA_EN_S  0
+
+/* I2S_CLKM_CONF_REG register
+ * I2S module clock configure register
+ */
+
+#define I2S_CLKM_CONF_REG(i) (REG_I2S_BASE(i) + 0xac)
+
+/* I2S_CLKA_ENA : R/W; bitpos: [21]; default: 0;
+ * Set this bit to enable clk_apll.
+ */
+
+#define I2S_CLKA_ENA    (BIT(21))
+#define I2S_CLKA_ENA_M  (I2S_CLKA_ENA_V << I2S_CLKA_ENA_S)
+#define I2S_CLKA_ENA_V  0x00000001
+#define I2S_CLKA_ENA_S  21
+
+/* I2S_CLK_ENA : R/W; bitpos: [21]; default: 0;
+ * Set this bit to enable clk_apll.
+ */
+
+#define I2S_CLK_ENA    (BIT(20))
+#define I2S_CLK_ENA_M  (I2S_CLK_ENA_V << I2S_CLK_ENA_S)
+#define I2S_CLK_ENA_V  0x00000001
+#define I2S_CLK_ENA_S  20
+
+/* I2S_CLKM_DIV_A : R/W; bitpos: [19:14]; default: 0;
+ * Fractional clock divider denominator value
+ */
+
+#define I2S_CLKM_DIV_A    0x0000003F
+#define I2S_CLKM_DIV_A_M  (I2S_CLKM_DIV_A_V << I2S_CLKM_DIV_A_S)
+#define I2S_CLKM_DIV_A_V  0x0000003F
+#define I2S_CLKM_DIV_A_S  14
+
+/* I2S_CLKM_DIV_B : R/W; bitpos: [13:8]; default: 0;
+ * Fractional clock divider numerator value
+ */
+
+#define I2S_CLKM_DIV_B    0x0000003F
+#define I2S_CLKM_DIV_B_M  (I2S_CLKM_DIV_B_V << I2S_CLKM_DIV_B_S)
+#define I2S_CLKM_DIV_B_V  0x0000003F
+#define I2S_CLKM_DIV_B_S  8
+
+/* I2S_CLKM_DIV_NUM : R/W; bitpos: [7:0]; default: 4;
+ * Integral I2S clock divider value
+ */
+
+#define I2S_CLKM_DIV_NUM    0x000000FF
+#define I2S_CLKM_DIV_NUM_M  (I2S_CLKM_DIV_NUM_V << I2S_CLKM_DIV_NUM_S)
+#define I2S_CLKM_DIV_NUM_V  0x000000FF
+#define I2S_CLKM_DIV_NUM_S  0
+
+/* I2S_SAMPLE_RATE_CONF_REG register
+ * I2S sample rate register
+ */
+
+#define I2S_SAMPLE_RATE_CONF_REG(i) (REG_I2S_BASE(i) + 0xb0)
+
+/* I2S_RX_BITS_MOD : R/W; bitpos: [23:18]; default: 16;
+ * Set the bits to configure bit length of I2S receiver channel.
+ */
+
+#define I2S_RX_BITS_MOD    0x0000003F
+#define I2S_RX_BITS_MOD_M  (I2S_RX_BITS_MOD_V << I2S_RX_BITS_MOD_S)
+#define I2S_RX_BITS_MOD_V  0x0000003F
+#define I2S_RX_BITS_MOD_S  18
+
+/* I2S_TX_BITS_MOD : R/W; bitpos: [17:12]; default: 16;
+ * Set the bits to configure bit length of I2S transmitter channel.
+ */
+
+#define I2S_TX_BITS_MOD    0x0000003F
+#define I2S_TX_BITS_MOD_M  (I2S_TX_BITS_MOD_V << I2S_TX_BITS_MOD_S)
+#define I2S_TX_BITS_MOD_V  0x0000003F
+#define I2S_TX_BITS_MOD_S  12
+
+/* I2S_RX_BCK_DIV_NUM : R/W; bitpos: [11:6]; default: 6;
+ * 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  0x0000003F
+#define I2S_RX_BCK_DIV_NUM_S  6
+
+/* I2S_TX_BCK_DIV_NUM : R/W; bitpos: [5:0]; default: 6;
+ * 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  0x0000003F
+#define I2S_TX_BCK_DIV_NUM_S  0
+
+/* I2S_PDM_CONF_REG register
+ * I2S PDM configuration register
+ */
+
+#define I2S_PDM_CONF_REG(i) (REG_I2S_BASE(i) + 0xb4)
+
+/* I2S_TX_PDM_HP_BYPASS : R/W; bitpos: [25]; default: 0;
+ * Set this bit to bypass the transmitter's PDM HP filter.
+ */
+
+#define I2S_TX_PDM_HP_BYPASS    BIT(25)
+#define I2S_TX_PDM_HP_BYPASS_M  (I2S_TX_PDM_HP_BYPASS_V << 
I2S_TX_PDM_HP_BYPASS_S)
+#define I2S_TX_PDM_HP_BYPASS_V  0x00000001
+#define I2S_TX_PDM_HP_BYPASS_S  25
+
+/* I2S_RX_PDM_SINC_DSR_16_EN : R/W; bitpos: [24]; default: 1;
+ * PDM downsampling rate for filter group 1 in receiver mode.
+ * 1: downsampling rate = 128; 0: downsampling rate = 64
+ */
+
+#define I2S_RX_PDM_SINC_DSR_16_EN   BIT(24)
+#define I2S_RX_PDM_SINC_DSR_16_EN_M (I2S_RX_PDM_SINC_DSR_16_EN_V << 
I2S_RX_PDM_SINC_DSR_16_EN_S)
+#define I2S_RX_PDM_SINC_DSR_16_EN_V 0x00000001
+#define I2S_RX_PDM_SINC_DSR_16_EN_S 24
+
+/* I2S_TX_PDM_SIGMADELTA_IN_SHIFT : R/W; bitpos: [23:22]; default: 1;
+ * Adjust the size of the input signal into filter module.
+ * 0: divided by 2; 1: multiplied by 1;
+ * 2: multiplied by 2; 3: multiplied by 4.
+ */
+
+#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    0x00000003
+#define I2S_TX_PDM_SIGMADELTA_IN_SHIFT_S    22
+
+/* I2S_TX_PDM_SINC_IN_SHIFT : R/W; bitpos: [21:20]; default: 1;
+ * Adjust the size of the input signal into filter module.
+ * 0: divided by 2; 1: multiplied by 1;
+ * 2: multiplied by 2; 3: multiplied by 4.
+ */
+
+#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  0x00000003
+#define I2S_TX_PDM_SINC_IN_SHIFT_S  20
+
+/* I2S_TX_PDM_LP_IN_SHIFT : R/W; bitpos: [19:18]; default: 1;
+ * Adjust the size of the input signal into filter module.
+ * 0: divided by 2; 1: multiplied by 1;
+ * 2: multiplied by 2; 3: multiplied by 4.
+ */
+
+#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    0x00000003
+#define I2S_TX_PDM_LP_IN_SHIFT_S    18
+
+/* I2S_TX_PDM_HP_IN_SHIFT : R/W; bitpos: [17:16]; default: 1;
+ * Adjust the size of the input signal into filter module.
+ * 0: divided by 2; 1: multiplied by 1;
+ * 2: multiplied by 2; 3: multiplied by 4.
+ */
+
+#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    0x00000003
+#define I2S_TX_PDM_HP_IN_SHIFT_S    16
+
+/* I2S_TX_PDM_SINC_OSR2 : R/W; bitpos: [7:4]; default: 2;
+ * Upsampling rate = 64×i2s_tx_pdm_sinc_osr2
+ */
+
+#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  0x0000000F
+#define I2S_TX_PDM_SINC_OSR2_S  4
+
+/* I2S_PDM2PCM_CONV_EN : R/W; bitpos: [3]; default: 1;
+ * Set this bit to enable PDM-to-PCM converter.
+ */
+
+#define I2S_PDM2PCM_CONV_EN     BIT(3)
+#define I2S_PDM2PCM_CONV_EN_M   (I2S_PDM2PCM_CONV_EN_V << 
I2S_PDM2PCM_CONV_EN_S)
+#define I2S_PDM2PCM_CONV_EN_V   0x00000001
+#define I2S_PDM2PCM_CONV_EN_S   3
+
+/* I2S_PCM2PDM_CONV_EN : R/W; bitpos: [2]; default: 1;
+ * Set this bit to enable PCM-to-PDM converter.
+ */
+
+#define I2S_PCM2PDM_CONV_EN     BIT(2)
+#define I2S_PCM2PDM_CONV_EN_M   (I2S_PCM2PDM_CONV_EN_V << 
I2S_PCM2PDM_CONV_EN_S)
+#define I2S_PCM2PDM_CONV_EN_V   0x00000001
+#define I2S_PCM2PDM_CONV_EN_S   2
+
+/* I2S_RX_PDM_EN : R/W; bitpos: [1]; default: 0;
+ * Set this bit to enable receiver’s PDM mode.
+ */
+
+#define I2S_RX_PDM_EN       BIT(1)
+#define I2S_RX_PDM_EN_M     (I2S_RX_PDM_EN_V << I2S_RX_PDM_EN_S)
+#define I2S_RX_PDM_EN_V     0x00000001
+#define I2S_RX_PDM_EN_S     1
+
+/* I2S_TX_PDM_EN : R/W; bitpos: [0]; default: 0;
+ * Set this bit to enable transmitter’s PDM mode.
+ */
+
+#define I2S_TX_PDM_EN       BIT(0)
+#define I2S_TX_PDM_EN_M     (I2S_TX_PDM_EN_V << I2S_TX_PDM_EN_S)
+#define I2S_TX_PDM_EN_V     0x00000001
+#define I2S_TX_PDM_EN_S     0
+
+/* I2S_PDM_FREQ_CONF_REG register
+ * I2S PDM frequencies register
+ */
+
+#define I2S_PDM_FREQ_CONF_REG(i) (REG_I2S_BASE(i) + 0xb8)
+
+/* I2S_TX_PDM_FP : R/W; bitpos: [19:10]; default: 960;
+ * PCM-to-PDM converter’s PDM frequency parameter.
+ */
+
+#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     0x000003FF
+#define I2S_TX_PDM_FP_S     10
+
+/* I2S_TX_PDM_FS : R/W; bitpos: [9:0]; default: 441;
+ * PCM-to-PDM converter’s PCM frequency parameter.
+ */
+
+#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     0x000003FF
+#define I2S_TX_PDM_FS_S     0
+
+/* I2S_STATE_REG register
+ * I2S TX status register
+ */
+
+#define I2S_STATE_REG(i) (REG_I2S_BASE(i) + 0xbc)
+
+/* I2S_RX_FIFO_RESET_BACK : RO; bitpos: [2]; default: 0;
+ * This bit is used to confirm if the Rx FIFO reset is done.
+ * 1: reset is not ready; 0: reset is ready.
+ */
+
+#define I2S_RX_FIFO_RESET_BACK      (BIT(2))
+#define I2S_RX_FIFO_RESET_BACK_M    (I2S_RX_FIFO_RESET_BACK_V << 
I2S_RX_FIFO_RESET_BACK_S)
+#define I2S_RX_FIFO_RESET_BACK_V    0x00000001
+#define I2S_RX_FIFO_RESET_BACK_S    2
+
+/* I2S_TX_FIFO_RESET_BACK : RO; bitpos: [1]; default: 0;
+ * 1: I2S TX is in idle state. 0: I2S TX is busy.
+ */
+
+#define I2S_TX_FIFO_RESET_BACK      (BIT(1))
+#define I2S_TX_FIFO_RESET_BACK_M    (I2S_TX_FIFO_RESET_BACK_V << 
I2S_TX_FIFO_RESET_BACK_S)
+#define I2S_TX_FIFO_RESET_BACK_V    0x00000001
+#define I2S_TX_FIFO_RESET_BACK_S    1
+
+/* I2S_TX_IDLE : RO; bitpos: [0]; default: 1;
+ * 1: I2S TX is in idle state. 0: I2S TX is busy.
+ */
 
-#define I2S_FIFO_FORCE_PU       (BIT(1))
-#define I2S_FIFO_FORCE_PU_M     (BIT(1))
-#define I2S_FIFO_FORCE_PU_V     0x1
-#define I2S_FIFO_FORCE_PU_S     1
+#define I2S_TX_IDLE    (BIT(0))
+#define I2S_TX_IDLE_M  (I2S_TX_IDLE_V << I2S_TX_IDLE_S)
+#define I2S_TX_IDLE_V  0x00000001
+#define I2S_TX_IDLE_S  0
 
 #endif /* __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_I2S_H */
diff --git a/boards/xtensa/esp32/common/src/Make.defs 
b/boards/xtensa/esp32/common/src/Make.defs
index a6f53e6476..fdfde999db 100644
--- a/boards/xtensa/esp32/common/src/Make.defs
+++ b/boards/xtensa/esp32/common/src/Make.defs
@@ -32,6 +32,10 @@ ifeq ($(CONFIG_I2C_DRIVER),y)
   CSRCS += esp32_board_i2c.c
 endif
 
+ifeq ($(CONFIG_ESP32_I2S),y)
+  CSRCS += esp32_board_i2sdev.c
+endif
+
 ifeq ($(CONFIG_I2CMULTIPLEXER_TCA9548A),y)
   CSRCS += esp32_tca9548a.c
 endif
diff --git a/boards/xtensa/esp32/common/src/esp32_board_i2sdev.c 
b/boards/xtensa/esp32/common/src/esp32_board_i2sdev.c
new file mode 100644
index 0000000000..4ac9555a9b
--- /dev/null
+++ b/boards/xtensa/esp32/common/src/esp32_board_i2sdev.c
@@ -0,0 +1,109 @@
+/****************************************************************************
+ * boards/xtensa/esp32/common/src/esp32_board_i2sdev.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 <nuttx/config.h>
+
+#include <stdio.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/audio/audio.h>
+#include <nuttx/audio/audio_i2s.h>
+#include <nuttx/audio/i2s.h>
+#include <nuttx/audio/pcm.h>
+
+#include <arch/board/board.h>
+
+#include "esp32_i2s.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_i2sdev_initialize
+ *
+ * Description:
+ *   This function is called by platform-specific, setup logic to configure
+ *   and register the generic I2S audio driver.  This function will register
+ *   the driver as /dev/audio/pcm[x] where x is determined by the I2S port
+ *   number.
+ *
+ * Input Parameters:
+ *   port  - The I2S port used for the device
+ *
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int board_i2sdev_initialize(int port)
+{
+  struct audio_lowerhalf_s *audio_i2s;
+  struct audio_lowerhalf_s *pcm;
+  struct i2s_dev_s *i2s;
+  char devname[12];
+  int ret;
+
+  ainfo("Initializing I2S\n");
+
+  i2s = esp32_i2sbus_initialize(port);
+
+#ifdef CONFIG_AUDIO_I2SCHAR
+  ret = i2schar_register(i2s, 0);
+  if (ret < 0)
+    {
+      aerr("ERROR: i2schar_register failed: %d\n", ret);
+      return ret;
+    }
+#endif
+
+  audio_i2s = audio_i2s_initialize(i2s, true);
+
+  if (!audio_i2s)
+    {
+      auderr("ERROR: Failed to initialize I2S\n");
+      return -ENODEV;
+    }
+
+  pcm = pcm_decode_initialize(audio_i2s);
+
+  if (!pcm)
+    {
+      auderr("ERROR: Failed create the PCM decoder\n");
+      return  -ENODEV;
+    }
+
+  snprintf(devname, 12, "pcm%d", port);
+
+  ret = audio_register(devname, pcm);
+
+  if (ret < 0)
+    {
+      auderr("ERROR: Failed to register /dev/%s device: %d\n", devname, ret);
+    }
+
+  return ret;
+}
diff --git a/boards/xtensa/esp32/esp32-devkitc/configs/i2schar/defconfig 
b/boards/xtensa/esp32/esp32-devkitc/configs/i2schar/defconfig
new file mode 100644
index 0000000000..dcf9c709fa
--- /dev/null
+++ b/boards/xtensa/esp32/esp32-devkitc/configs/i2schar/defconfig
@@ -0,0 +1,62 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_ARCH_LEDS is not set
+# CONFIG_ESP32_I2S0_RX is not set
+# CONFIG_NDEBUG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_CMDPARMS is not set
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32-devkitc"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32_DEVKITC=y
+CONFIG_ARCH_CHIP="esp32"
+CONFIG_ARCH_CHIP_ESP32=y
+CONFIG_ARCH_CHIP_ESP32WROVER=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_AUDIO=y
+CONFIG_AUDIO_I2S=y
+CONFIG_AUDIO_I2SCHAR=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DRIVERS_AUDIO=y
+CONFIG_ESP32_I2S0=y
+CONFIG_ESP32_I2S0_MCLK=y
+CONFIG_ESP32_I2S=y
+CONFIG_ESP32_UART0=y
+CONFIG_EXAMPLES_I2SCHAR=y
+CONFIG_EXAMPLES_I2SCHAR_TX=y
+CONFIG_EXAMPLES_I2SCHAR_TXBUFFERS=2
+CONFIG_EXAMPLES_I2SCHAR_TXSTACKSIZE=4096
+CONFIG_FS_PROCFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INIT_STACKSIZE=4096
+CONFIG_INTELHEX_BINARY=y
+CONFIG_MM_REGIONS=3
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/xtensa/esp32/esp32-devkitc/src/esp32-devkitc.h 
b/boards/xtensa/esp32/esp32-devkitc/src/esp32-devkitc.h
index b919197eae..6f64f0d3d5 100644
--- a/boards/xtensa/esp32/esp32-devkitc/src/esp32-devkitc.h
+++ b/boards/xtensa/esp32/esp32-devkitc/src/esp32-devkitc.h
@@ -151,5 +151,27 @@ int board_spidev_initialize(int bus);
 int esp32_twai_setup(void);
 #endif
 
+/****************************************************************************
+ * Name: board_i2sdev_initialize
+ *
+ * Description:
+ *   This function is called by platform-specific, setup logic to configure
+ *   and register the generic I2S audio driver.  This function will register
+ *   the driver as /dev/audio/pcm[x] where x is determined by the I2S port
+ *   number.
+ *
+ * Input Parameters:
+ *   port  - The I2S port used for the device
+ *
+ * Returned Value:
+ *   Zero is returned on success.  Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+#if defined CONFIG_ESP32_I2S0 || defined CONFIG_ESP32_I2S1
+int board_i2sdev_initialize(int port);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_XTENSA_ESP32_ESP32_DEVKITC_SRC_ESP32_DEVKITC_H */
diff --git a/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c 
b/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c
index 766c5d9cd1..a5849946b4 100644
--- a/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c
+++ b/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c
@@ -87,6 +87,10 @@
 #  include "esp32_board_i2c.h"
 #endif
 
+#ifdef CONFIG_ESP32_I2S
+#  include "esp32_i2s.h"
+#endif
+
 #ifdef CONFIG_I2CMULTIPLEXER_TCA9548A
 #  include "esp32_tca9548a.h"
 #endif
@@ -453,6 +457,36 @@ int esp32_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_ESP32_I2S
+
+#ifdef CONFIG_ESP32_I2S0
+
+  /* Configure I2S generic audio on I2S0 */
+
+  ret = board_i2sdev_initialize(ESP32_I2S0);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize I2S%d driver: %d\n",
+             CONFIG_ESP32_I2S0, ret);
+    }
+
+#endif  /* CONFIG_ESP32_I2S0 */
+
+#ifdef CONFIG_ESP32_I2S1
+
+  /* Configure I2S generic audio on I2S1 */
+
+  ret = board_i2sdev_initialize(ESP32_I2S1);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize I2S%d driver: %d\n",
+             CONFIG_ESP32_I2S0, ret);
+    }
+
+#endif  /* CONFIG_ESP32_I2S1 */
+
+#endif /* CONFIG_ESP32_I2S */
+
 #ifdef CONFIG_SENSORS_SHT3X
   /* Try to register SHT3x device in I2C0 */
 


Reply via email to