diff --git a/os/arch/arm/src/amebasmart/amebasmart_i2s.c b/os/arch/arm/src/amebasmart/amebasmart_i2s.c index d1a495b33c..3f60a3e2cc 100644 --- a/os/arch/arm/src/amebasmart/amebasmart_i2s.c +++ b/os/arch/arm/src/amebasmart/amebasmart_i2s.c @@ -168,6 +168,9 @@ struct amebasmart_i2s_config_s { uint8_t i2s_idx; /* I2S index*/ uint8_t rxenab : 1; /* True: RX transfers enabled */ uint8_t txenab : 1; /* True: TX transfers enabled */ +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + uint8_t tdmenab: 1; /* True: TDM is enabled */ +#endif }; /* The state of the one I2S peripheral */ @@ -180,12 +183,20 @@ struct amebasmart_i2s_s { #if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) uint8_t i2s_tx_buf[(I2S_DMA_PAGE_NUM + 1) * I2S_DMA_PAGE_SIZE]__attribute__((aligned(64))); /* Allocate buffer for use in TX, must I2S_DMA_PAGE_NUM+1 for zero buffer */ i2s_irq_handler tx_isr_handler; +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + uint8_t i2s_tx_buf_ext[(I2S_DMA_PAGE_NUM + 1) * I2S_DMA_PAGE_SIZE]__attribute__((aligned(64))); /* Allocate buffer for use in TX, must I2S_DMA_PAGE_NUM+1 for zero buffer */ + i2s_irq_handler tx_isr_handler_ext; +#endif #endif #if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) //uint8_t i2s_rx_buf[(I2S_DMA_PAGE_NUM + 1) * I2S_DMA_PAGE_SIZE]__attribute__((aligned(64))); /* Allocate buffer for use in RX, must I2S_DMA_PAGE_NUM+1 for zero buffer */ uint8_t* i2s_rx_buf; i2s_irq_handler rx_isr_handler; +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + uint8_t* i2s_rx_buf_ext; + i2s_irq_handler rx_isr_handler_ext; +#endif #endif i2s_err_cb_t err_cb; /* registered error callback function */ @@ -195,6 +206,9 @@ struct amebasmart_i2s_s { uint8_t rxenab : 1; /* True: RX transfers enabled */ uint8_t txenab : 1; /* True: TX transfers enabled */ +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + uint8_t tdmenab : 1; /* True: TDM Enabled (this will disable MULTIIO)*/ +#endif int sample_rate; /*!< I2S sample rate */ int channel_num; /*!< Number of channels */ @@ -227,6 +241,9 @@ static const struct amebasmart_i2s_config_s amebasmart_i2s2_config = { .i2s_idx = I2S_NUM_2, .rxenab = 0, .txenab = 1, +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + .tdmenab = 0, +#endif }; static const struct amebasmart_i2s_config_s amebasmart_i2s3_config = { @@ -239,8 +256,27 @@ static const struct amebasmart_i2s_config_s amebasmart_i2s3_config = { .i2s_idx = I2S_NUM_3, .rxenab = 1, .txenab = 0, +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + .tdmenab = 0, +#endif }; +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) +/* currently support I2S2 */ +static const struct amebasmart_i2s_config_s amebasmart_i2s2_tdm_config = { + .i2s_mclk_pin = PB_22, + .i2s_sclk_pin = PB_21, + .i2s_ws_pin = PA_16, + .i2s_sd_tx_pin = PB_10, + .i2s_sd_rx_pin = PB_19, + + .i2s_idx = I2S_NUM_2, + .rxenab = 1, + .txenab = 0, + .tdmenab = 1, +}; +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -340,6 +376,28 @@ static const struct i2s_ops_s g_i2sops = { .i2s_err_cb_register = i2s_err_cb_register, }; +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) +/* I2S device operations */ +static const struct i2s_ops_s g_i2stdm_ops = { + /* Receiver methods */ + + .i2s_rxsamplerate = i2s_samplerate, + .i2s_rxdatawidth = i2s_rxdatawidth, + .i2s_receive = i2s_receive, + + /* Transmitter methods */ + + .i2s_txsamplerate = i2s_samplerate, + .i2s_txdatawidth = i2s_txdatawidth, + .i2s_send = i2s_send, + + .i2s_stop = i2s_stop, + .i2s_pause = i2s_pause, + .i2s_resume = i2s_resume, + .i2s_err_cb_register = i2s_err_cb_register, +}; +#endif + static struct amebasmart_i2s_s *g_i2sdevice[I2S_NUM_MAX] = {NULL}; /**************************************************************************** @@ -1413,13 +1471,21 @@ static int i2s_pause(struct i2s_dev_s *dev, i2s_ch_dir_t dir) #if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) if (dir == I2S_TX && priv->txenab) { - ameba_i2s_pause(priv->i2s_object); + if (priv->tdmenab) { + ameba_i2s_tdm_pause(priv->i2s_object); + } else { + ameba_i2s_pause(priv->i2s_object); + } } #endif #if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) if (dir == I2S_RX && priv->rxenab) { - ameba_i2s_pause(priv->i2s_object); + if (priv->tdmenab) { + ameba_i2s_tdm_pause(priv->i2s_object); + } else { + ameba_i2s_pause(priv->i2s_object); + } } #endif @@ -1447,13 +1513,21 @@ static int i2s_resume(struct i2s_dev_s *dev, i2s_ch_dir_t dir) #if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) if (dir == I2S_TX && priv->txenab) { - ameba_i2s_resume(priv->i2s_object); + if (priv->tdmenab) { + ameba_i2s_tdm_resume(priv->i2s_object); + } else { + ameba_i2s_resume(priv->i2s_object); + } } #endif #if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) if (dir == I2S_RX && priv->rxenab) { - ameba_i2s_resume(priv->i2s_object); + if (priv->tdmenab) { + ameba_i2s_tdm_resume(priv->i2s_object); + } else { + ameba_i2s_resume(priv->i2s_object); + } } #endif @@ -1480,13 +1554,17 @@ static int i2s_stop_transfer(struct i2s_dev_s *dev, i2s_ch_dir_t dir) DEBUGASSERT(priv); #if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) - if (dir == I2S_TX) { + if (dir == I2S_TX && priv->tdmenab) { + ameba_i2s_tdm_pause(priv->i2s_object); + } else { ameba_i2s_pause(priv->i2s_object); } #endif #if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) - if (dir == I2S_RX) { + if (dir == I2S_RX && priv->tdmenab) { + ameba_i2s_tdm_pause(priv->i2s_object); + } else { ameba_i2s_pause(priv->i2s_object); } #endif @@ -1619,6 +1697,20 @@ int amebasmart_i2s_isr_initialize(struct amebasmart_i2s_s *priv) return 0; } +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) +int amebasmart_i2s_tdm_isr_initialize(struct amebasmart_i2s_s *priv) +{ + /* Attach the GPIO peripheral to the allocated CPU interrupt */ +#if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) + i2s_tdm_tx_irq_handler(priv->i2s_object, (i2s_irq_handler)priv->tx_isr_handler, (uint32_t)priv); +#endif +#if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) + i2s_tdm_rx_irq_handler(priv->i2s_object, (i2s_irq_handler)priv->rx_isr_handler, (uint32_t)priv); +#endif + return 0; +} +#endif + /**************************************************************************** * Name: i2s_samplerate * @@ -1713,6 +1805,33 @@ static void i2s_getdefaultconfig(struct amebasmart_i2s_s *priv) } priv->i2s_object->mode = MULTIIO; + + /* modify configurations if TDM is enabled */ +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + if (priv->config->tdmenab) { + dbg("init for tdm: %d \n", priv->config->tdmenab); + /* TDM configuration fixed for ais25ba */ + priv->i2s_object->mode = TDM; + priv->i2s_object->role = MASTER; + priv->i2s_object->direction = SP_DIR_RX; + + /* sample rate */ + priv->i2s_object->sampling_rate = SP_16K; + priv->sample_rate = SP_16K; + + /* num channels */ + priv->i2s_object->channel_num = SP_CH_STEREO; + priv->channel_num = SP_CH_STEREO; + + /* word and channel length */ + priv->bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT; + priv->i2s_object->word_length = WL_16b; // SP_RXWL_16; + priv->i2s_object->channel_length = SP_CL_16; + + /* FIFO size */ + priv->i2s_object->fifo_num = SP_RX_FIFO8; // for 8ch tdm + } +#endif } /**************************************************************************** @@ -1768,7 +1887,7 @@ static int i2s_allocate_wd(struct amebasmart_i2s_s *priv) ****************************************************************************/ /**************************************************************************** - * Name: amebasmart_i2s_initialize + * Name: amebasmart_i2s_tdm_initialize * * Description: * Initialize the selected i2s port @@ -1879,6 +1998,121 @@ struct i2s_dev_s *amebasmart_i2s_initialize(uint16_t port, bool is_reinit) kmm_free(priv); return NULL; } + +struct i2s_dev_s *amebasmart_i2s_tdm_initialize(uint16_t port, bool is_reinit) +{ + struct amebasmart_i2s_config_s *hw_config_s = NULL; + struct amebasmart_i2s_s *priv; + int ret; + + /* Assign HW configuration */ + if (port == I2S_NUM_2) { + hw_config_s = (struct amebasmart_i2s_config_s *)&amebasmart_i2s2_tdm_config; // TDM config on I2S2 + } else { + i2serr("Please select I2S2 bus for TDM\n"); + return NULL; + } + + if (!is_reinit) { + if (g_i2sdevice[port] != NULL) { + return &g_i2sdevice[port]->dev; + } + + /* Allocate a new state structure for this chip select. NOTE that there + * is no protection if the same chip select is used in two different + * chip select structures. + */ + priv = (struct amebasmart_i2s_s *)kmm_zalloc(sizeof(struct amebasmart_i2s_s)); + if (!priv) { + i2serr("ERROR: Failed to allocate a chip select structure\n"); + return NULL; + } + } else { + /* The I2S structure should exist after system wakeup */ + priv = g_i2sdevice[port]; + DEBUGASSERT(priv); + } + + priv->i2s_object = (i2s_t *)kmm_zalloc(sizeof(i2s_t)); + DEBUGASSERT(priv->i2s_object); + /* Config values initialization */ + priv->config = hw_config_s; /* Get HW configuation */ + + /* Get default configuration */ + i2s_getdefaultconfig(priv); + + /* Initialize buffering */ +#if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) + i2s_buf_rx_initialize(priv); +#endif + +#if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) + i2s_buf_tx_initialize(priv); +#endif + printf("tdmenab: %d \n", priv->config->tdmenab); + printf("ChLen: %d \n", priv->i2s_object->channel_length); + printf("WLen: %d \n", priv->i2s_object->word_length); + printf("ChNum: %d \n", priv->i2s_object->channel_num); + printf("SR: %d \n", priv->i2s_object->sampling_rate); + printf("FIFOnum: %d \n", priv->i2s_object->fifo_num); + + //Init_Params.chn_cnt = (sp_obj.tdmmode + 1) * 2; + /* I2s object initialization */ + i2s_tdm_init(priv->i2s_object, hw_config_s->i2s_sclk_pin, hw_config_s->i2s_ws_pin, hw_config_s->i2s_sd_tx_pin, hw_config_s->i2s_sd_rx_pin, hw_config_s->i2s_mclk_pin); + + /* Initialize buffering */ +#if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) + i2s_set_dma_buffer(priv->i2s_object, (char *)priv->i2s_tx_buf, NULL, I2S_DMA_PAGE_NUM, I2S_DMA_PAGE_SIZE); /* Allocate DMA Buffer for TX */ +#endif + + /* configures IRQ */ +#if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) + priv->rx_isr_handler = (i2s_irq_handler)&i2s_transfer_rx_handleirq; + +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + priv->rx_isr_handler_ext = (i2s_irq_handler)&i2s_transfer_rx_handleirq; +#endif + +#endif + +#if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) + priv->tx_isr_handler = (i2s_irq_handler)&i2s_transfer_tx_handleirq; + +#if defined(I2S_HAVE_TDM) && (0 < I2S_HAVE_TDM) + priv->tx_isr_handler_ext = (i2s_irq_handler)&i2s_transfer_tx_handleirq; +#endif + +#endif + + //ret = amebasmart_i2s_isr_initialize(priv); + ret = amebasmart_i2s_tdm_isr_initialize(priv); // TDM + if (ret != OK) { + i2serr("I2S initialize (TDM): isr fails\n"); + goto errout_with_alloc; + } + /* Initialize the I2S priv device structure */ + sem_init(&priv->exclsem, 0, 1); + priv->dev.ops = &g_i2stdm_ops; // TDM + + ret = i2s_allocate_wd(priv); + if (ret != OK) { + goto errout_with_alloc; + } + /* Basic settings */ + //priv->i2s_num = priv->i2s_object->i2s_idx; + if (!is_reinit) { + g_i2sdevice[port] = priv; + } + + /* Success exit */ + return &priv->dev; + + /* Failure exits */ +errout_with_alloc: + sem_destroy(&priv->exclsem); + kmm_free(priv); + return NULL; +} #endif /* I2S_HAVE_RX || I2S_HAVE_TX */ #endif /* CONFIG_AUDIO */ @@ -1891,7 +2125,7 @@ static void amebasmart_i2s_suspend(uint16_t port) kmm_free(priv->i2s_object); priv->i2s_object = NULL; sem_destroy(&priv->exclsem); - sem_destroy(&priv->bufsem_tx); + #if defined(I2S_HAVE_RX) && (0 < I2S_HAVE_RX) if (priv->rx.dog) { wd_delete(priv->rx.dog); @@ -1899,6 +2133,7 @@ static void amebasmart_i2s_suspend(uint16_t port) } #endif #if defined(I2S_HAVE_TX) && (0 < I2S_HAVE_TX) + sem_destroy(&priv->bufsem_tx); if (priv->tx.dog) { wd_delete(priv->tx.dog); priv->tx.dog = NULL; diff --git a/os/board/rtl8730e/src/component/mbed/targets/hal/rtl8730e/i2s_api.c b/os/board/rtl8730e/src/component/mbed/targets/hal/rtl8730e/i2s_api.c index 11c027b24e..13bcd2733e 100755 --- a/os/board/rtl8730e/src/component/mbed/targets/hal/rtl8730e/i2s_api.c +++ b/os/board/rtl8730e/src/component/mbed/targets/hal/rtl8730e/i2s_api.c @@ -383,10 +383,17 @@ static uint32_t i2s_clock_select(i2s_t *obj) uint32_t clock_mode = 0; AUDIO_ClockParams Clock_Params; AUDIO_InitParams Init_Params; - +#if defined(CONFIG_AMEBASMART_I2S_TDM) + Init_Params.chn_len = obj->channel_length; + Init_Params.chn_cnt = (obj->fifo_num + 1) * 2; +#else Init_Params.chn_len = SP_CL_32; Init_Params.chn_cnt = obj->channel_num; - Init_Params.sr = obj->sampling_rate;; +#endif + + + Init_Params.sr = obj->sampling_rate; + dbg("ChLen: %d ChCnt: %d Sr: %d\n", obj->channel_length, obj->channel_num, obj->sampling_rate); Init_Params.codec_multiplier_with_rate = 256; Init_Params.sport_mclk_fixed_max = (uint32_t) NULL; Audio_Clock_Choose(PLL_CLK, &Init_Params, &Clock_Params); @@ -415,6 +422,7 @@ static uint32_t i2s_clock_select(i2s_t *obj) clock_mode = PLL_CLOCK_98P304M / Clock_Params.PLL_DIV; break; } + dbg("CLK: %d mode: %f div: %d\n", Clock_Params.Clock, clock_mode, Clock_Params.PLL_DIV); return clock_mode; } @@ -608,6 +616,13 @@ void i2s_recv_page(i2s_t *obj) */ void i2s_enable(i2s_t *obj) { +#if defined(CONFIG_AMEBASMART_I2S_TDM) + // turn on MCLK if master + if (obj->role == MASTER) { + AUDIO_SP_SetMclk(obj->i2s_idx, ENABLE); + } +#endif + AUDIO_SP_DmaCmd(obj->i2s_idx, ENABLE); if (obj->direction == I2S_DIR_TX) { AUDIO_SP_TXStart(obj->i2s_idx, ENABLE); @@ -625,20 +640,40 @@ void i2s_disable(i2s_t *obj, bool is_suspend) { SP_GDMA_STRUCT *l_SPGdmaStruct = &SPGdmaStruct; +#if defined(CONFIG_AMEBASMART_I2S_TDM) + SP_GDMA_STRUCT_EXT *l_SPGdmaStructExt = &SPGdmaStructExt; + // turn off MCLK if master + if (obj->role == MASTER) { + AUDIO_SP_SetMclk(obj->i2s_idx, DISABLE); + } +#endif + if (obj->direction == I2S_DIR_TX) { GDMA_ClearINT(l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_ChNum); GDMA_Abort(l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_ChNum); GDMA_ChnlFree(l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_ChNum); + +#if defined(CONFIG_AMEBASMART_I2S_TDM) && defined(CONFIG_AMEBASMART_I2S_TX) + GDMA_ClearINT(l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_ChNum); + GDMA_Abort(l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_ChNum); + GDMA_ChnlFree(l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_ChNum); +#endif + AUDIO_SP_DmaCmd(obj->i2s_idx, DISABLE); AUDIO_SP_TXStart(obj->i2s_idx, DISABLE); if (is_suspend) { AUDIO_SP_Deinit(obj->i2s_idx, obj->direction); } } else { - GDMA_ClearINT(l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_ChNum); GDMA_Cmd(l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_ChNum, DISABLE); +#if defined(CONFIG_AMEBASMART_I2S_TDM) && defined(CONFIG_AMEBASMART_I2S_RX) + GDMA_ClearINT(l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_ChNum); + GDMA_Abort(l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_ChNum); + GDMA_ChnlFree(l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_ChNum); +#endif + AUDIO_SP_DmaCmd(obj->i2s_idx, DISABLE); AUDIO_SP_RXStart(obj->i2s_idx, DISABLE); } @@ -661,6 +696,31 @@ void ameba_i2s_pause(i2s_t *obj) { } } +#ifdef CONFIG_AMEBASMART_I2S_TDM +void ameba_i2s_tdm_pause(i2s_t *obj) { + + SP_GDMA_STRUCT *l_SPGdmaStruct = &SPGdmaStruct; + SP_GDMA_STRUCT_EXT *l_SPGdmaStructExt = &SPGdmaStructExt; + +#if defined(CONFIG_AMEBASMART_I2S_TDM) + // turn on MCLK if master + if (obj->role == MASTER) { + AUDIO_SP_SetMclk(obj->i2s_idx, DISABLE); + } +#endif + + if (obj->direction == I2S_DIR_TX) { + GDMA_ClearINT(l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpTxGdmaInitStruct.GDMA_ChNum); + GDMA_ClearINT(l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpTxGdmaInitStructExt.GDMA_ChNum); + AUDIO_SP_DmaCmd(obj->i2s_idx, DISABLE); + AUDIO_SP_TXStart(obj->i2s_idx, DISABLE); + } else { + GDMA_Suspend(l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_ChNum); + GDMA_Suspend(l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_ChNum); + } +} +#endif + /** * @brief Resume I2S interrupt and function. * @param obj: I2S object defined in application software. @@ -677,7 +737,29 @@ void ameba_i2s_resume(i2s_t *obj) { } } -#if defined(CONFIG_AMEBASMART_I2S_TDM) +#ifdef CONFIG_AMEBASMART_I2S_TDM +void ameba_i2s_tdm_resume(i2s_t *obj) { + + SP_GDMA_STRUCT *l_SPGdmaStruct = &SPGdmaStruct; + SP_GDMA_STRUCT_EXT *l_SPGdmaStructExt = &SPGdmaStructExt; + + // turn on MCLK if master + if (obj->role == MASTER) { + AUDIO_SP_SetMclk(obj->i2s_idx, ENABLE); + } + + if (obj->direction == I2S_DIR_TX) { + AUDIO_SP_DmaCmd(obj->i2s_idx, ENABLE); + AUDIO_SP_TXStart(obj->i2s_idx, ENABLE); + } else { + GDMA_Resume(l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_Index, l_SPGdmaStruct->SpRxGdmaInitStruct.GDMA_ChNum); + GDMA_Resume(l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_Index, l_SPGdmaStructExt->SpRxGdmaInitStructExt.GDMA_ChNum); + } +} +#endif + +#if defined(CONFIG_AMEBASMART_I2S_TDM) +#if defined(CONFIG_AMEBASMART_I2S_TX) && (CONFIG_AMEBASMART_I2S_TX == 1) static void i2s_tdm_tx_isr(void *sp_data) { u32 *pbuf; @@ -712,6 +794,36 @@ static void i2s_tdm_tx_isr_ext(void *sp_data) I2SUserCB.TxCCB(I2SUserCB.TxCBId, (char*)pbuf); } +/** + * @brief Register TX interrupt handler. + * @param obj: I2S object defined in application software. + * @param handler: TX interrupt callback function. + * @param id: TX interrupt callback parameter. + * @retval none + */ +void i2s_tdm_tx_irq_handler(i2s_t *obj, i2s_irq_handler handler, uint32_t id) +{ + assert_param(IS_SP_SEL_I2S(obj->i2s_idx)); + + uint8_t i2s_index = obj->i2s_idx; + SP_GDMA_STRUCT *sp_str = &SPGdmaStruct; + SP_GDMA_STRUCT_EXT *sp_str_ext = &SPGdmaStructExt; + u32 *pbuf, pbuf_1; + + sp_str->i2s_idx = i2s_index; /* Store I2S index */ + sp_str_ext->i2s_idx = i2s_index; + + I2SUserCB.TxCCB = handler; + I2SUserCB.TxCBId = id; + + pbuf = (u32 *)i2s_get_ready_tx_page(i2s_index); + pbuf_1 = (u32 *)i2s_get_ready_tx_page(i2s_index); + AUDIO_SP_TXGDMA_Init(i2s_index, GDMA_INT, &sp_str->SpTxGdmaInitStruct, sp_str, (IRQ_FUN)i2s_tdm_tx_isr, (u8 *)pbuf, sp_tx_info.tx_page_size); + AUDIO_SP_TXGDMA_Init(i2s_index, GDMA_EXT, &sp_str_ext->SpTxGdmaInitStructExt, sp_str_ext, (IRQ_FUN)i2s_tdm_tx_isr_ext, (u8 *)pbuf_1, sp_tx_info.tx_page_size); +} +#endif + +#if defined(CONFIG_AMEBASMART_I2S_RX) && (CONFIG_AMEBASMART_I2S_RX == 1) static void i2s_tdm_rx_isr(void *sp_data) { SP_GDMA_STRUCT *gs = sp_data; @@ -750,34 +862,6 @@ static void i2s_tdm_rx_isr_ext(void *sp_data) i2s_get_free_rx_page(i2s_index); } -/** - * @brief Register TX interrupt handler. - * @param obj: I2S object defined in application software. - * @param handler: TX interrupt callback function. - * @param id: TX interrupt callback parameter. - * @retval none - */ -void i2s_tdm_tx_irq_handler(i2s_t *obj, i2s_irq_handler handler, uint32_t id) -{ - assert_param(IS_SP_SEL_I2S(obj->i2s_idx)); - - uint8_t i2s_index = obj->i2s_idx; - SP_GDMA_STRUCT *sp_str = &SPGdmaStruct; - SP_GDMA_STRUCT_EXT *sp_str_ext = &SPGdmaStructExt; - u32 *pbuf, pbuf_1; - - sp_str->i2s_idx = i2s_index; /* Store I2S index */ - sp_str_ext->i2s_idx = i2s_index; - - I2SUserCB.TxCCB = handler; - I2SUserCB.TxCBId = id; - - pbuf = (u32 *)i2s_get_ready_tx_page(i2s_index); - pbuf_1 = (u32 *)i2s_get_ready_tx_page(i2s_index); - AUDIO_SP_TXGDMA_Init(i2s_index, GDMA_INT, &sp_str->SpTxGdmaInitStruct, sp_str, (IRQ_FUN)i2s_tdm_tx_isr, (u8 *)pbuf, sp_tx_info.tx_page_size); - AUDIO_SP_TXGDMA_Init(i2s_index, GDMA_EXT, &sp_str_ext->SpTxGdmaInitStructExt, sp_str_ext, (IRQ_FUN)i2s_tdm_tx_isr_ext, (u8 *)pbuf_1, sp_tx_info.tx_page_size); -} - /** * @brief Register RX interrupt handler. * @param obj: I2S object defined in application software. @@ -806,6 +890,8 @@ void i2s_tdm_rx_irq_handler(i2s_t *obj, i2s_irq_handler handler, uint32_t id) AUDIO_SP_RXGDMA_Init(i2s_index, GDMA_EXT, &sp_str_ext->SpRxGdmaInitStructExt, sp_str_ext, (IRQ_FUN)i2s_tdm_rx_isr_ext, (u8 *)pbuf_1, sp_rx_info.rx_page_size); } +#endif + /** * @brief Enable I2S interrupt and function. * @param obj: I2S object defined in application software. @@ -915,12 +1001,14 @@ void i2s_tdm_set_param(i2s_t *obj, int channel_num, int rate, int word_len) SP_InitStruct.SP_SelClk = clock_mode; AUDIO_SP_Init(obj->i2s_idx, obj->direction, &SP_InitStruct); + dbg("SP_BClk: %ld Hz\n", SP_InitStruct.SP_Bclk); + AUDIO_SP_SetMasterSlave(obj->i2s_idx, obj->role); if (obj->role == MASTER) { - AUDIO_SP_SetMclk(obj->i2s_idx, ENABLE); + //AUDIO_SP_SetMclk(obj->i2s_idx, ENABLE); AUDIO_SP_SetMclkDiv(obj->i2s_idx, 0); } else { - AUDIO_SP_SetMclk(obj->i2s_idx, DISABLE); + //AUDIO_SP_SetMclk(obj->i2s_idx, DISABLE); } } @@ -980,6 +1068,8 @@ void i2s_tdm_init(i2s_t *obj, PinName sck, PinName ws, PinName sd_tx, PinName sd RCC_PeriphClockCmd(APBPeriph_SPORT3, APBPeriph_SPORT3_CLOCK, ENABLE); } + RCC_PeriphClockCmd(APBPeriph_AUDIO, APBPeriph_CLOCK_NULL, ENABLE); + Pinmux_Config(mck, pin_func); Pinmux_Config(sck, pin_func); Pinmux_Config(ws, pin_func); diff --git a/os/board/rtl8730e/src/rtl8730e_i2schar.c b/os/board/rtl8730e/src/rtl8730e_i2schar.c index c570d4ce46..7a83b3811e 100644 --- a/os/board/rtl8730e/src/rtl8730e_i2schar.c +++ b/os/board/rtl8730e/src/rtl8730e_i2schar.c @@ -42,6 +42,10 @@ #ifndef CONFIG_AMEBASMART_I2SCHAR_MINOR_3 #define CONFIG_AMEBASMART_I2SCHAR_MINOR_3 3 #endif + +#ifndef CONFIG_AMEBASMART_I2SCHAR_MINOR_4 +#define CONFIG_AMEBASMART_I2SCHAR_MINOR_4 4 +#endif /***************************************************************************** * Private Functions ****************************************************************************/ @@ -74,15 +78,22 @@ int i2schar_devinit(void) #if defined(CONFIG_AMEBASMART_I2S2) && !defined(CONFIG_AUDIO_ALC1019) /* Call amebasmart_i2s_initialize() to get an instance of the I2S interface */ /* Initialise I2S2 */ +#if defined(CONFIG_AMEBASMART_I2S_TDM) + i2s = amebasmart_i2s_tdm_initialize(I2S_NUM_2, I2S_INIT); +#else i2s = amebasmart_i2s_initialize(I2S_NUM_2, I2S_INIT); - +#endif if (!i2s) { lldbg("ERROR: Failed to get the amebasmart I2S driver\n"); return -ENODEV; } /* Register the I2S character driver at "/dev/i2schar2" */ +#if defined(CONFIG_AMEBASMART_I2S_TDM) + ret = i2schar_register(i2s, CONFIG_AMEBASMART_I2SCHAR_MINOR_4); +#else ret = i2schar_register(i2s, CONFIG_AMEBASMART_I2SCHAR_MINOR_2); +#endif if (ret < 0) { lldbg("ERROR: i2schar_register failed: %d\n", ret); return ret;