Files
E3_boot/drivers/include/sdrv_i2s.h
2025-11-07 10:05:24 +08:00

420 lines
13 KiB
C

/**
* @file sdrv_i2s.h
* @brief SemiDrive I2S driver header file.
*
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
* All rights reserved.
*/
#ifndef SDRV_I2S_DRIVER_H_
#define SDRV_I2S_DRIVER_H_
#include <debug.h>
#include <reg.h>
#include <stdbool.h>
#include <types.h>
#include "sdrv_ckgen.h"
#include "sdrv_common.h"
#include "sdrv_dma.h"
#define SDRV_I2S_DAIFMT_FORMAT_MASK 0x0f
/* i2s standard phillips interface mode */
#define SDRV_I2S_DAIFMT_STANDARD_PHILLIPS 1
/* i2s left justified interface mode */
#define SDRV_I2S_DAIFMT_LEFT_JUSTIFIED 2
/* i2s right justified interface mode */
#define SDRV_I2S_DAIFMT_RIGHT_JUSTIFIED 3
/* i2s dsp mode-A */
#define SDRV_I2S_DAIFMT_DSP_A 4
/* i2s dsp mode-B */
#define SDRV_I2S_DAIFMT_DSP_B 5
/* transfer control mode master or slave */
#define SDRV_I2S_DAIFMT_MASTER_MASK (0x0f0)
#define SDRV_I2S_DAIFMT_CODEC_SLAVE (1 << 4)
#define SDRV_I2S_DAIFMT_CODEC_MASTER (2 << 4)
#define SDRV_I2S_DAIFMT_INV_MASK 0x0f00
#define SDRV_I2S_DAIFMT_INV_OFFSET 8
/* normal bit clock + frame */
#define SDRV_I2S_DAIFMT_NB_NF (0 << SDRV_I2S_DAIFMT_INV_OFFSET)
/* normal BCLK + inv FRM */
#define SDRV_I2S_DAIFMT_NB_IF (SDRV_I2S_DAIFMT_INV_OFFSET)
/* invert BCLK + nor FRM */
#define SDRV_I2S_DAIFMT_IB_NF (3 << SDRV_I2S_DAIFMT_INV_OFFSET)
/* invert BCLK + FRM */
#define SDRV_I2S_DAIFMT_IB_IF (4 << SDRV_I2S_DAIFMT_INV_OFFSET)
#define SDRV_I2S_XFER_NUM_BUFFERS (4U)
#define SDRV_I2S_CHNNELS_COUNT 2
#define SDRV_I2S_CHNNELS_BYTES (SDRV_I2S_SAMPLE_WIDTH_16BITS / 8)
#define SDRV_I2S_DMA_PERIOD_FRAME_SIZE 1024 * 4
#define SDRV_I2S_DMA_PERIOD_BYTES \
SDRV_I2S_DMA_PERIOD_FRAME_SIZE *SDRV_I2S_CHNNELS_COUNT \
*SDRV_I2S_CHNNELS_BYTES
#define SDRV_I2S_DMA_PERIOD_COUNT 2
#define SDRV_I2S_DMA_BUF_TOTAL_SIZE \
SDRV_I2S_DMA_PERIOD_SIZE *SDRV_I2S_DMA_PERIOD_COUNT
#define SDRV_I2S_SEL_CHNULL 0x00
#define SDRV_I2S_SEL_DATALINE0 (0x01 << 0)
#define SDRV_I2S_SEL_DATALINE1 (0x01 << 1)
#define SDRV_I2S_SEL_DATALINE2 (0x01 << 2)
#define SDRV_I2S_SEL_DATALINE3 (0x01 << 3)
#define SDRV_I2S_SEL_DATALINE4 (0x01 << 4)
#define SDRV_I2S_SEL_DATALINE5 (0x01 << 5)
#define SDRV_I2S_SEL_DATALINE6 (0x01 << 6)
#define SDRV_I2S_SEL_DATALINE7 (0x01 << 7)
/**
* @brief i2s channel num
*
*/
typedef enum i2s_channel {
SDRV_I2S_CHANNEL_NUM_MONO = 1,
SDRV_I2S_CHANNEL_NUM_STEREO = 2,
SDRV_I2S_CHANNEL_NUM_3CHANS = 3,
SDRV_I2S_CHANNEL_NUM_4CHANS = 4,
SDRV_I2S_CHANNEL_NUM_5CHANS = 5,
SDRV_I2S_CHANNEL_NUM_6CHANS = 6,
SDRV_I2S_CHANNEL_NUM_7CHANS = 7,
SDRV_I2S_CHANNEL_NUM_8CHANS = 8,
SDRV_I2S_CHANNEL_NUM_9CHANS = 9,
SDRV_I2S_CHANNEL_NUM_10CHANS = 10,
SDRV_I2S_CHANNEL_NUM_11CHANS = 11,
SDRV_I2S_CHANNEL_NUM_12CHANS = 12,
SDRV_I2S_CHANNEL_NUM_13CHANS = 13,
SDRV_I2S_CHANNEL_NUM_14CHANS = 14,
SDRV_I2S_CHANNEL_NUM_15CHANS = 15,
SDRV_I2S_CHANNEL_NUM_16CHANS = 16,
} sdrv_i2s_channel_t;
/**
* @brief i2s sample rate
*
*/
typedef enum sdrv_i2s_sample_rate {
SDRV_I2S_SR_NO_INIT = 0,
SDRV_I2S_SR_5512 = 5512,
SDRV_I2S_SR_8000 = 8000,
SDRV_I2S_SR_11025 = 11025,
SDRV_I2S_SR_16000 = 16000,
SDRV_I2S_SR_22050 = 22050,
SDRV_I2S_SR_32000 = 32000,
SDRV_I2S_SR_44100 = 44100,
SDRV_I2S_SR_48000 = 48000,
SDRV_I2S_SR_64000 = 64000,
SDRV_I2S_SR_88200 = 88200,
SDRV_I2S_SR_96000 = 96000,
SDRV_I2S_SR_176400 = 176400,
SDRV_I2S_SR_192000 = 192000,
} sdrv_i2s_sample_rate_t;
/**
* @brief sample width
*
*/
typedef enum sdrv_i2s_sample_width {
SDRV_I2S_SAMPLE_WIDTH_8BITS = 8,
SDRV_I2S_SAMPLE_WIDTH_16BITS = 16,
SDRV_I2S_SAMPLE_WIDTH_24BITS = 24,
SDRV_I2S_SAMPLE_WIDTH_32BITS = 32,
} sdrv_i2s_sample_width_t;
/**
* @brief slot width
*
*/
typedef enum sdrv_i2s_slot_width {
SDRV_I2S_SLOT_WIDTH_8BITS = 8,
SDRV_I2S_SLOT_WIDTH_16BITS = 16,
SDRV_I2S_SLOT_WIDTH_24BITS = 24,
SDRV_I2S_SLOT_WIDTH_32BITS = 32,
} sdrv_i2s_slot_width_t;
/**
* @brief playback capture type
*
*/
typedef enum {
SDRV_I2S_STREAM_PLAYBACK = 0,
SDRV_I2S_STREAM_CAPTURE,
SDRV_I2S_STREAM_MAX,
} sdrv_i2s_stream_type_t;
/**
* @brief sdrv i2s sync mode ,select sck and ws source
*
*/
typedef enum sdrv_i2s_clk_sync_type {
/**< tx clk synchronization, rx will shares tx clk */
SDRV_I2S_CLK_TX_SYNC = 0,
/**< rx clk synchronization, tx will shares rx clk */
SDRV_I2S_CLK_RX_SYNC,
/**< async mode,tx and rx work on their respective clocks*/
SDRV_I2S_CLK_TX_RX_ASYNC,
} sdrv_i2s_clk_sync_type_t;
/**
* @brief i2s dma buff descriptions,which is used to transfer data in dma mod
*
*
*/
typedef struct sdrv_i2s_dma_buf {
uint8_t *addr; /**< dma mode ,buffer address */
uint32_t buffer_bytes; /**< buffer size */
uint32_t period_bytes; /**< one period size */
uint32_t periods; /**< period count */
uint32_t appl_ptr; /**< app write pointer during playback, dma read pointer
during capture */
uint32_t hw_ptr; /**< dma read pointer during playback, dma write pointer
during capture */
uint32_t boundary; /**< dma buff boundary */
} sdrv_i2s_dma_buf_t;
typedef enum sdrv_i2s_status {
/**< status for Success. */
SDRV_I2S_STATUS_SUCCESS = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_COMMON, 0),
/**< status for Fail. */
SDRV_I2S_STATUS_FAIL = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_I2S, 1),
/**< status for invalid argument check*/
SDRV_I2S_STATUS_INVALID_PARAMS =
SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_I2S, 2),
/**< status for overrun */
SDRV_I2S_STATUS_OVERRUN = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_I2S, 3),
/**< status for underrun */
SDRV_I2S_STATUS_UNDERRUN = SDRV_ERROR_STATUS(SDRV_STATUS_GROUP_I2S, 4),
} sdrv_i2s_status_t;
/**
* @brief sdrv i2s transfer descriptions
*
*/
typedef struct sdrv_i2s_transfer {
uint8_t *data; /**< audio data addr */
uint32_t length; /**< audio data length */
uint8_t id; /**< transfer tag */
} sdrv_i2s_transfer_t;
/* @brief sdrv i2s transfer callback function. */
typedef void (*sdrv_i2s_callback)(sdrv_i2s_transfer_t *transfer, void *context,
sdrv_i2s_status_t state);
/**
* @brief sdrv i2s configurations params,
*
*/
typedef struct sdrv_i2s_params {
uint32_t fmt; /**< i2s data format */
sdrv_i2s_channel_t channels; /**< data channels */
sdrv_i2s_sample_width_t sample_width; /**< data width */
sdrv_i2s_sample_rate_t sample_rate; /**< data sample rate */
unsigned int period_bytes; /**< dma mode need set, dma generates an
interrupt transmission data size */
unsigned int periods; /**< dma mode need set, period num */
sdrv_i2s_channel_t slots; /**< slot num */
sdrv_i2s_slot_width_t slot_width; /* slot data width */
unsigned int tx_slot_mask; /**< slot mask ,1 :slot enable; 0:slot disable */
unsigned int rx_slot_mask; /**< slot mask ,1 :slot enable; 0:slot disable */
bool usedma; /**< true :dma mode; false:irq mode */
uint8_t *dma_buff; /**< dma mode need set dma_buf addr,
size=period_count*period_size */
} sdrv_i2s_params_t;
/**
* @brief i2s mclk direction selection in or out
*
*/
typedef enum sdrv_i2s_mclk_dir {
SDRV_I2S_MCLK_IN = 0, /**< i2s mclk in */
SDRV_I2S_MCLK_OUT, /**< i2s mclk out,default out */
} sdrv_i2s_mclk_dir_t;
/**
* @brief i2s mclk selection mclk0 or mclk1
*
*/
typedef enum sdrv_i2s_mclk_sel {
SDRV_I2S_MCLK_NULL = 0,
SDRV_I2S_MCLK_0,
SDRV_I2S_MCLK_1,
} sdrv_i2s_mclk_sel_t;
/**
* @brief i2s controller configurations
*
*/
typedef struct sdrv_i2s_config {
paddr_t base; /**< i2s module base addr */
int id; /**< reserved */
uint32_t irq; /**< i2s module irq num */
sdrv_ckgen_node_t *clk; /**< i2s module clk */
paddr_t dma_base; /**< dma used by i2s, which is dma base addr */
sdrv_dma_channel_id_e
tx_channel_id; /**< dma used by i2s, which is dma channel */
sdrv_dma_channel_id_e
rx_channel_id; /**< dma used by i2s, which is dma channel */
sdrv_i2s_clk_sync_type_t sync_mode; /**< tx rx synchronization */
uint8_t tx_chsel; /**< tx data pin */
uint8_t rx_chsel; /**< rx data pin */
sdrv_i2s_mclk_dir_t mclk_dir; /**< mclk in or out ,default out */
sdrv_i2s_mclk_sel_t mclk_sel; /**< which mclk is selected */
} sdrv_i2s_config_t;
/**
* @brief i2s dma fifo descriptions
*
*/
typedef struct sdrv_i2s_dma_data {
paddr_t addr; /**< i2s fifo base addr */
sdrv_dma_bus_width_e addr_width; /**< i2s fifo width */
unsigned int maxburst; /**< i2s fifo max transfer size */
unsigned int fifo_size; /**< i2s fifo fifo size */
} sdrv_i2s_dma_data_t;
/**
* @brief playback capture descriptions
*
*/
typedef struct sdrv_i2s_stream {
/**< i2s config params ;such as fmt channels sample_width sample_rate */
sdrv_i2s_params_t params;
/**< stream status; true : running false:idle */
bool active;
/**< clk status; true for enable ; false for disable */
bool clk_enable;
/**< data pack mode in fifo */
bool pack_mode;
/**< i2s request dma transfer when fifo data is >= threshold for playback
* i2s request dma transfer when fifo data is <= threshold for capture
*/
unsigned threshold;
/**< app transfer queue , the max size is SDRV_I2S_XFER_NUM_BUFFERS */
sdrv_i2s_transfer_t queue[SDRV_I2S_XFER_NUM_BUFFERS];
uint8_t queue_appl; /**< app submit enqueue transfer index */
uint8_t queue_hw; /**< hw dequeue transfer index */
/**< app callback to notify user transfer status */
sdrv_i2s_callback callback;
/**< callback context */
void *context;
/**< dma module instance handle */
sdrv_dma_t dma_instance;
/**< dma module channel handle */
sdrv_dma_channel_t dma_channel;
/**< i2s dma fifo descriptions */
sdrv_i2s_dma_data_t dma_data;
/**< dma buff descriptions */
sdrv_i2s_dma_buf_t dma_buf;
} sdrv_i2s_stream_t;
/**
* @brief i2s controller descriptions
*
*/
typedef struct sdrv_i2s {
sdrv_i2s_config_t *cfg; /**< i2s module cfg infomation */
uint32_t clk_rate; /**< i2s module work clk rate */
sdrv_i2s_stream_t stream[2]; /**< playback capture descriptions */
} sdrv_i2s_t;
/**
* @brief initializes i2s module controller
*
* This fuction initializes i2s module
* function.
*
* @param [in] i2s sdrv i2s controller
* @param [in] cfg sdrv i2s controller configurations
* @return sdrv_i2s_status_t
*
*/
sdrv_i2s_status_t sdrv_i2s_init(sdrv_i2s_t *i2s, sdrv_i2s_config_t *cfg);
/**
* @brief get i2s module default params
*
* This fuction is used to get i2s module default params
*
* @param [in] i2s sdrv i2s controller
* @param [out] params sdrv i2s params
* @param [in] type playback or capture type
* @return sdrv_i2s_status_t
*
*/
sdrv_i2s_status_t sdrv_i2s_get_default_params(sdrv_i2s_t *i2s,
sdrv_i2s_params_t *params,
sdrv_i2s_stream_type_t type);
/**
* @brief set i2s params
*
* This fuction is used to set i2s module params
*
* @param [in] i2s sdrv i2s controller
* @param [in] params sdrv i2s params
* @param [in] type playback or capture type
* @ return sdrv_i2s_status_t
*
*
*/
sdrv_i2s_status_t sdrv_i2s_set_params(sdrv_i2s_t *i2s,
sdrv_i2s_params_t *params,
sdrv_i2s_stream_type_t type);
/**
* @brief create i2s transfer and attach callback
*
* This fuction is used to create transfer and attach transfer callback
*
* @param [in] i2s sdrv i2s controller
* @param [in] callback sdrv i2s transfer callback function.
* @param [in] context sdrv i2s transfer callback param.
* @param [in] type playback or capture type
* @return sdrv_i2s_status_t
*/
sdrv_i2s_status_t sdrv_i2s_create_transfer(sdrv_i2s_t *i2s,
sdrv_i2s_callback callback,
void *context,
sdrv_i2s_stream_type_t type);
/**
* @brief submit i2s transfer in queue
*
* This fuction is used to submit transfer, which's max num is
* SDRV_I2S_XFER_NUM_BUFFERS
*
* @param [in] i2s sdrv i2s controller
* @param [in] transfer sdrv i2s transfer
* @param [in] type playback or capture type
* @return sdrv_i2s_status_t
*/
sdrv_i2s_status_t sdrv_i2s_submit_transfer(sdrv_i2s_t *i2s,
sdrv_i2s_transfer_t *transfer,
sdrv_i2s_stream_type_t type);
/**
* @brief start i2s transfer
*
* This fuction is used to start i2s transfer
*
* @param [in] i2s sdrv i2s controller
* @param [in] type playback or capture type
* @return sdrv_i2s_status_t
*/
sdrv_i2s_status_t sdrv_i2s_start(sdrv_i2s_t *i2s, sdrv_i2s_stream_type_t type);
/**
* @brief stop i2s transfer
*
* * This fuction is used to stop i2s transfer
*
* @param [in] i2s sdrv i2s controller
* @param [in] type playback or capture type
* @return sdrv_i2s_status_t
*/
sdrv_i2s_status_t sdrv_i2s_stop(sdrv_i2s_t *i2s, sdrv_i2s_stream_type_t type);
#endif /* SDRV_I2S_DRIVER_H_ */