/*
* Copyright (c) 2006­2020, RT­Thread Development Team
*
* SPDX­License­Identifier: Apache­2.0
*
* Change Logs:
* Date          Author      Notes
* 2023­06­07  weijiac     the first version
* 2023-06-26    weijiac     add interface for drv_asi.c
*/

#ifndef _HAL_ASI_H_
#define _HAL_ASI_H_

#include <stdlib.h>
#include <stdbool.h>
//#include <hal_interrupt.h>

//#include <hal_log.h>
//#include <gpio/gpio.h>
#include <hal_gpio.h>
#include "platform.h"
#include "hal_dma.h"
#include "hal_audio.h"

//same as DEV_ASI0 DEV_ASI1
#define ASIx(x) ((DEV_ASIn_RegDef_f *) ((uint32_t)(0x20140000+0x10000*x)))




typedef enum
{
    ASI0,
    ASI1
} asi_t;

/** This enum defines the data mode of ASI. */
typedef enum
{
    ASI_I2S_STANDARD        = 0x04UL,
    ASI_I2S_JUSTIFYLEFT     = 0x00UL,
    ASI_I2S_JUSTIFYRIGHT    = 0x08UL,
    ASI_PCM_MODEA           = 0x05UL,
    ASI_PCM_MODEB           = 0x01UL,
    ASI_SPDIF               = 0x02UL,
    ASI_DSD_LSB             = (0x04UL) | DEV_ASIn_CFG_DSD_CTL_DSD_CTLON | DEV_ASIn_CFG_LSB_MODE_LSB,
    ASI_DSD_MSB             = (0x04UL) | DEV_ASIn_CFG_DSD_CTL_DSD_CTLON | DEV_ASIn_CFG_LSB_MODE_MSB,
} asi_data_mode_t;

/** This enum defines to select Master mode or slave mode*/
typedef enum
{
    ASI_SLAVE_MODE  = DEV_ASIn_CFG_MASTER_SLAVE_MODE,
    ASI_MASTER_MODE =  DEV_ASIn_CFG_MASTER_MASTERMODE
} asi_master_mode_t;

/** This enum defines the channel number*/
typedef enum
{
    ASI_ONE_CHANNEL     = 0x0UL << 4,
    ASI_TWO_CHANNEL     = 0x1UL << 4,
    ASI_THREE_CHANNEL   = 0x2UL << 4,
    ASI_FOUR_CHANNEL    = 0x3UL << 4,
    ASI_FIVE_CHANNEL    = 0x4UL << 4,
    ASI_SIX_CHANNEL     = 0x5UL << 4,
    ASI_SEVEN_CHANNEL   = 0x6UL << 4,
    ASI_EIGHT_CHANNEL   = 0x7UL << 4,
} asi_chn_num_t;

/** This enum defines the channel width*/
typedef enum
{
    ASI_CHANNEL_WIDTH_16BITS = DEV_ASIn_CFG_CHN_WIDTH_16BCLKCYCLE,
    ASI_CHANNEL_WIDTH_32BITS = DEV_ASIn_CFG_CHN_WIDTH_32BCLKCYCLE,
} asi_chn_width_t;

/** This enum defines the DSD use selection*/
typedef enum
{
    ASI_DSD_OFF = DEV_ASIn_CFG_DSD_CTL_DSD_CTLOFF,
    ASI_DSD_ON  = DEV_ASIn_CFG_DSD_CTL_DSD_CTLON
} asi_dsd_ctl_t;

/** This enum defines the width of fifo */
typedef enum
{
    ASI_SAMPLE_BIT_16BITS   = DEV_ASIn_CFG_VLD_WIDTH_16BIT,
    ASI_SAMPLE_BIT_24BITS   = DEV_ASIn_CFG_VLD_WIDTH_24BIT,
    ASI_SAMPLE_BIT_32BITS   = DEV_ASIn_CFG_VLD_WIDTH_32BIT
} asi_sample_bit_t;

/** This enum defines the data format*/
typedef enum
{
    //data valid position in fifo
    ASI_DAT_FMT_HIGH_16BITS = DEV_ASIn_CFG_DAT_FMT_HIGH16BIT,
    ASI_DAT_FMT_LOW_16BITS  = DEV_ASIn_CFG_DAT_FMT_LOW_16BIT,
    ASI_DAT_FMT_HIGH_24BITS = DEV_ASIn_CFG_DAT_FMT_HIGH24BIT,
    ASI_DAT_FMT_LOW_24BITS  = DEV_ASIn_CFG_DAT_FMT_LOW_24BIT
} asi_data_format_t;


typedef enum
{
    ASI_TX_FIFO_THRESHOLD_8 = 0x08UL << 16,
    ASI_TX_FIFO_THRESHOLD_16 = 0x10UL << 16,
    ASI_TX_FIFO_THRESHOLD_32 = 0x20UL << 16
} asi_tx_fifo_threshold_t;

/** This enum defines the dsd data format*/
typedef enum
{
    ASI_DSD_DAT_FMT_HIGH_16BITS = DEV_ASIn_CFG_DSD_DAT_FMT_HIGH16BIT,
    ASI_DSD_DAT_FMT_LOW_16BITS = DEV_ASIn_CFG_DSD_DAT_FMT_LOW_16BIT,
    ASI_DSD_DAT_FMT_MIDDLE_16BITS = DEV_ASIn_CFG_DSD_DAT_FMT_MIDDLE16BIT,
    ASI_DSD_DAT_FMT_32BITS = DEV_ASIn_CFG_DSD_DAT_FMT_32BIT
} asi_dsd_dat_fmt_t;

typedef enum
{
    ASI_RX_FIFO_THRESHOLD_8  = 0x08UL << 24,
    ASI_RX_FIFO_THRESHOLD_16 = 0x10UL << 24,
    ASI_RX_FIFO_THRESHOLD_32 = 0x20UL << 24
} asi_rx_fifo_threshold_t;

typedef enum
{
    ASI_DSD_MSB_MODE = DEV_ASIn_CFG_LSB_MODE_MSB,
    ASI_DSD_LSB_MODE = DEV_ASIn_CFG_LSB_MODE_LSB,
} asi_dsd_dat_mode_t;

typedef enum
{
    ASI_TX_ENABLE  = DEV_ASIn_CTL_TX_EN_ENABLE,
    ASI_TX_DISABLE = DEV_ASIn_CTL_TX_EN_DISABLE
} asi_tx_enable_t;

typedef enum
{
    ASI_RX_ENABLE  = DEV_ASIn_CTL_RX_EN_ENABLE,
    ASI_RX_DISABLE = DEV_ASIn_CTL_RX_EN_DISABLE
} asi_rx_enable_t;

typedef enum
{
    ASI_TX_DMA_ENABLE  = DEV_ASIn_CTL_TX_DMA_EN_ENABLE,
    ASI_TX_DMA_DISABLE = DEV_ASIn_CTL_TX_DMA_EN_DISABLE
} asi_tx_dma_enable_t;

typedef enum
{
    ASI_RX_DMA_ENABLE  = DEV_ASIn_CTL_RX_DMA_EN_ENABLE,
    ASI_RX_DMA_DISABLE = DEV_ASIn_CTL_RX_DMA_EN_DISABLE
} asi_rx_dma_enable_t;

typedef enum
{
    ASI_TX_AHB  = DEV_ASIn_CTL_TX_SRC_SEL_AHB,
    ASI_TX_SRC  = DEV_ASIn_CTL_TX_SRC_SEL_SRC
} asi_tx_src_t;

typedef enum
{
    ASI_RX_AHB  = DEV_ASIn_CTL_RX_SRC_SEL_AHB,
    ASI_RX_SRC  = DEV_ASIn_CTL_RX_SRC_SEL_SRC
} asi_rx_src_t;


//Used for configuring the state of idle channels, generally set to a high impedance state to avoid data errors
typedef enum
{
    ASI_IO_STA_LOW  = DEV_ASIn_CTL_IO_STA_LOW_LEVEL,
    ASI_IO_STA_HIGH = DEV_ASIn_CTL_IO_STA_HIGH_LEVEL,
    ASI_IO_STA_HIGH_IMPEDANCE = DEV_ASIn_CTL_IO_STA_MASK
} asi_io_sta_t;

typedef enum
{
    ASI_CTL_TX_ENABLE       = DEV_ASIn_CTL_TX_EN_ENABLE,
    ASI_CTL_RX_ENABLE       = DEV_ASIn_CTL_RX_EN_ENABLE,
    ASI_CTL_TX_DMA_ENABLE   = DEV_ASIn_CTL_TX_DMA_EN_ENABLE,
    ASI_CTL_RX_DMA_ENABLE   = DEV_ASIn_CTL_RX_DMA_EN_ENABLE,
    ASI_CTL_TX_FIFO_RESET   = DEV_ASIn_CTL_TX_FIFO_RST_TXFIFORESET,
    ASI_CTL_RX_FIFO_RESET   = DEV_ASIn_CTL_RX_FIFO_RST_RXFIFORESET,
    ASI_CTL_TX_SRC_SEL      = DEV_ASIn_CTL_TX_SRC_SEL_SRC,
    ASI_CTL_RX_SRC_SEL      = DEV_ASIn_CTL_RX_SRC_SEL_SRC
} asi_control_option_t;

typedef enum
{
    ASI_IE_TX_IRQ       = DEV_ASIn_IE_TX_IRQ,
    ASI_IE_TX_FIFO_OF   = DEV_ASIn_IE_TX_FIFO_OF,
    ASI_IE_TX_FIFO_UF   = DEV_ASIn_IE_TX_FIFO_UF,
    ASI_IE_RX_IRQ       = DEV_ASIn_IE_RX_IRQ,
    ASI_IE_RX_FIFO_OF   = DEV_ASIn_IE_RX_FIFO_OF,
    ASI_IE_RX_FIFO_UF   = DEV_ASIn_IE_RX_FIFO_UF
} asi_interrupt_enable_option_t;

typedef enum
{
    ASI_PD_TX_IRQ       = DEV_ASIn_PD_TX_IRQ,
    ASI_PD_TX_FIFO_OF   = DEV_ASIn_PD_TX_FIFO_OF,
    ASI_PD_TX_FIFO_UF   = DEV_ASIn_PD_TX_FIFO_UF,
    ASI_PD_RX_IRQ       = DEV_ASIn_PD_RX_IRQ,
    ASI_PD_RX_FIFO_OF   = DEV_ASIn_PD_RX_FIFO_OF,
    ASI_PD_RX_FIFO_UF   = DEV_ASIn_PD_RX_FIFO_UF
} asi_interrupt_status_pending_t;

typedef enum
{
    ASI_TX_FIFO_WLVL = DEV_ASIn_STA_TX_FIFO_WLVL_MASK,
    ASI_TX_FIFO_AEMP = DEV_ASIn_STA_TX_FIFO_AEMP,
    ASI_TX_FIFO_EMPT = DEV_ASIn_STA_TX_FIFO_EMPT,
    ASI_TX_FIFO_AFUL = DEV_ASIn_STA_TX_FIFO_AFUL,
    ASI_TX_FIFO_FULL = DEV_ASIn_STA_TX_FIFO_FULL,
    ASI_TX_BUSY      = DEV_ASIn_STA_TX_BUSY,
    ASI_RX_FIFO_RLVL = DEV_ASIn_STA_RX_FIFO_RLVL_MASK,
    ASI_RX_FIFO_AEMP = DEV_ASIn_STA_RX_FIFO_AEMP,
    ASI_RX_FIFO_EMPT = DEV_ASIn_STA_RX_FIFO_EMPT,
    ASI_RX_FIFO_AFUL = DEV_ASIn_STA_RX_FIFO_AFUL,
    ASI_RX_FIFO_FULL = DEV_ASIn_STA_RX_FIFO_FULL,
    ASI_RX_BUSY      = DEV_ASIn_STA_RX_BUSY,
} asi_data_status_t;

typedef enum
{
    ASI_1_CHANNEL_ENABLE = (0b1UL) << 8,
    ASI_2_CHANNEL_ENABLE = (0b11UL) << 8,
    ASI_3_CHANNEL_ENABLE = (0b111UL) << 8,
    ASI_4_CHANNEL_ENABLE = (0b1111UL) << 8,
    ASI_5_CHANNEL_ENABLE = (0b11111UL) << 8,
    ASI_6_CHANNEL_ENABLE = (0b111111UL) << 8,
    ASI_7_CHANNEL_ENABLE = (0b1111111UL) << 8,
    ASI_8_CHANNEL_ENABLE = (0b11111111UL) << 8,
    ASI_CHANEL_MASK      = (0b11111111UL) << 8,
} asi_slot_ctl_t;

typedef enum
{
    ASI_CLK_OSC_XTAL = DEV_CMU_ASInCLK_SEL_OSC_XTAL,
    ASI_CLK_OSC_USB =   DEV_CMU_ASInCLK_SEL_OSC_USB,
    ASI_CLK_PLL_AUDIO =  DEV_CMU_ASInCLK_SEL_PLL_AUDIO,
    ASI_CLK_EXT_CLK =  DEV_CMU_ASInCLK_SEL_EXT_CLK,
}asi_clk_source_t;


typedef enum
{
    ASI_DISABLE = DISABLE,
    ASI_ENABLE = ENABLE,
} asi_enable_t;

//typedef struct asi_clk_typedef
//{
//    asi_clk_source_t clk_source;
//    uint32_t         clk_rate;
//    uint32_t         clk_sample_rate;
//    uint32_t         chn_nums;
//    uint32_t         chn_width;
//}asi_clk_typedef_t;

typedef struct asi_config_type
{
	asi_clk_source_t 		clk_source;
	uint32_t         		clk_rate;
	uint32_t				samplerate;
    asi_data_mode_t         data_mode;
    asi_master_mode_t       mode;
    asi_chn_num_t           chn_nums;
    asi_chn_width_t         chn_width;
    //asi_dsd_ctl_t           dsd_ctl;

    asi_sample_bit_t          sample_bit;
    asi_data_format_t       data_format ;
    //asi_dsd_dat_fmt_t       dsd_dat_fmt;
    //asi_dsd_dat_mode_t      dsd_dat_mode;


} asi_config_type_t;

typedef struct asi_control_type
{
    asi_tx_enable_t         tx_enable;
    asi_rx_enable_t         rx_enable;
    asi_tx_dma_enable_t     tx_dma_enable;
    asi_rx_dma_enable_t     rx_dma_enable;
    asi_tx_src_t            tx_stc_t;
    asi_rx_src_t            rx_stc_t;


    asi_slot_ctl_t          slot_enable;    /** 按位使能 **/
    asi_io_sta_t            io_sta;
} asi_control_type_t;

typedef struct asi_pins_type
{
    gpio_pin_t sck;
    gpio_pin_t ws;
    gpio_pin_t sdo;
    gpio_pin_t sdi;
} asi_pins_type_t;


typedef struct asi_interrupt_enable_type
{
    asi_enable_t asi_tx_irq_enable;
    asi_enable_t asi_tx_fifo_of_enable;
    asi_enable_t asi_tx_fifo_uf_enable;
    asi_enable_t asi_rx_irq_enable;
    asi_enable_t asi_rx_fifo_of_enable;
    asi_enable_t asi_rx_fifo_uf_enable;
} asi_interrupt_enable_type_t;

typedef struct asi_init_typedef
{
    uint32_t    asi_sample_rate;    //采样率
    uint32_t    asi_sample_bit;         //数据深度
    uint32_t    asi_clk_source;
    uint32_t    asi_clk_rate;
    const uint32_t  asix;
    uint32_t    data_mode;
    uint32_t    mode;
    uint32_t    chn_nums;
    uint32_t    chn_width;
    uint32_t    data_route;
} asi_init_typedef_t;

typedef struct asi_handle_typedef
{
    asi_init_typedef_t        init;
    DMA_HandleTypeDef           *dma_tx_handle; /*!< Pointer DMA Handler */
    DMA_HandleTypeDef           *dma_rx_handle;
    audio_state_type_def        state;
    uint32_t                    err_code;
} asi_handle_typedef_t;





//HAL_StatusTypeDef hal_asi_clk_init(asi_t asix, asi_clk_typedef_t *asi_clk_struct);

HAL_StatusTypeDef hal_asi_init(asi_t asix, asi_config_type_t *asi_config_struct,
                               asi_pins_type_t *pins, asi_control_type_t *asi_control_struct,
                               asi_interrupt_enable_type_t *enable_type);
HAL_StatusTypeDef hal_asi_config_init(asi_t asix, asi_config_type_t *asi_config_struct);

void hal_asi_control_init(asi_t asix, asi_control_type_t *asi_control_struct);
void hal_asi_pins_init(asi_pins_type_t *pins);
void hal_asi_interrupt_enable_init(asi_t asix, asi_interrupt_enable_type_t *enable_type);
void hal_asi_set_control_option(asi_t asix, asi_control_option_t ctl_option,
                                asi_enable_t enable_option);
uint32_t hal_asi_get_control_option(asi_t asix, asi_control_option_t ctl_option);
void hal_asi_set_interrupt_option(asi_t asix, asi_interrupt_enable_option_t interrupt_enbale_option,
                                  asi_enable_t enable_option);
uint32_t hal_asi_get_interrupt_option(asi_t asix, asi_interrupt_enable_option_t interrupt_enbale_option);
uint32_t hal_asi_interrupt_get_interrupt_status(asi_t asix, asi_interrupt_status_pending_t pdx);
void hal_asi_interrupt_clear_interrupt_pending(asi_t asix, asi_interrupt_status_pending_t pdx);
uint32_t hal_asi_get_data_status(asi_t asix, asi_data_status_t statux);
void hal_asi_reset(asi_t asix);
HAL_StatusTypeDef hal_asi_fill_tx_fifo(asi_t asix);
HAL_StatusTypeDef hal_asi_txfifo_reset(asi_t asix);
HAL_StatusTypeDef hal_asi_rxfifo_reset(asi_t asix);
HAL_StatusTypeDef get_asi_clk_div(uint32_t clk_rate,uint32_t samplerate, uint32_t chnx, uint32_t chn_width, uint32_t *addr);

HAL_StatusTypeDef hal_audio_asi_open(asi_t asix);
HAL_StatusTypeDef hal_audio_asi_close(asi_t asix);
HAL_StatusTypeDef hal_audio_asi_status(asi_t asix);
void hal_asi_rx_enable(asi_t asix,uint32_t option);
void hal_asi_tx_enable(asi_t asix,uint32_t option);

#endif  /*_HAL_ASI_H_*/
