/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #include "hal_i2s.h" #include "hal_cmu.h" #include "hal_i2sip.h" #include "hal_iomux.h" #include "plat_addr_map.h" #include "plat_types.h" #include "reg_i2sip.h" #if !defined(CHIP_BEST1000) && defined(I2S_MCLK_FROM_SPDIF) #include "hal_spdif.h" #endif #include "analog.h" #include "cmsis.h" #include "hal_timer.h" #include "hal_trace.h" // Trigger DMA request when TX-FIFO count <= threshold #define HAL_I2S_TX_FIFO_TRIGGER_LEVEL (I2SIP_FIFO_DEPTH / 2) // Trigger DMA request when RX-FIFO count >= threshold #define HAL_I2S_RX_FIFO_TRIGGER_LEVEL (I2SIP_FIFO_DEPTH / 2) #define HAL_I2S_YES 1 #define HAL_I2S_NO 0 #ifdef CHIP_BEST1000 #define I2S_CMU_DIV CODEC_PLL_DIV #define I2S_CHAN_NUM 1 #else #define I2S_CMU_DIV CODEC_CMU_DIV #define I2S_CHAN_NUM 4 #endif #ifndef I2S_MCLK_DIV #define I2S_MCLK_DIV 2 #endif enum HAL_I2S_STATUS_T { HAL_I2S_STATUS_NULL, HAL_I2S_STATUS_OPENED, HAL_I2S_STATUS_STARTED, }; struct I2S_SAMPLE_RATE_T { enum AUD_SAMPRATE_T sample_rate; uint32_t codec_freq; uint8_t codec_div; uint8_t cmu_div; }; struct HAL_I2S_MOD_NAME_T { enum HAL_CMU_MOD_ID_T mod; enum HAL_CMU_MOD_ID_T apb; }; static const struct I2S_SAMPLE_RATE_T i2s_sample_rate[] = { {AUD_SAMPRATE_8000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_16000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_32000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_44100, CODEC_FREQ_44_1K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_48000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_64000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_96000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_128000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_256000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_176400, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_192000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_352800, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_384000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_512000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_705600, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_768000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, {AUD_SAMPRATE_1024000, CODEC_FREQ_48K_SERIES, CODEC_PLL_DIV, I2S_CMU_DIV}, }; static const char *const invalid_id = "Invalid I2S ID: %d\n"; // static const char * const invalid_ch = "Invalid I2S CH: %d\n"; static enum HAL_I2S_STATUS_T i2s_status[HAL_I2S_ID_QTY][AUD_STREAM_NUM]; static enum HAL_I2S_MODE_T i2s_mode[HAL_I2S_ID_QTY]; static bool i2s_dma[HAL_I2S_ID_QTY][AUD_STREAM_NUM]; static bool sync_start[HAL_I2S_ID_QTY][AUD_STREAM_NUM]; #ifdef CHIP_BEST2000 static uint8_t i2s_rx_line_map[HAL_I2S_ID_QTY]; STATIC_ASSERT(sizeof(i2s_rx_line_map) * 8 >= I2S_CHAN_NUM, "i2s_rx_line_map size too small"); #endif static const struct HAL_I2S_MOD_NAME_T i2s_mod[HAL_I2S_ID_QTY] = { { .mod = HAL_CMU_MOD_O_I2S0, .apb = HAL_CMU_MOD_P_I2S0, }, #if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1) { .mod = HAL_CMU_MOD_O_I2S1, .apb = HAL_CMU_MOD_P_I2S1, }, #endif }; static inline uint32_t _i2s_get_reg_base(enum HAL_I2S_ID_T id) { ASSERT(id < HAL_I2S_ID_QTY, invalid_id, id); switch (id) { case HAL_I2S_ID_0: return I2S0_BASE; break; #if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1) case HAL_I2S_ID_1: return I2S1_BASE; break; #endif default: break; } return 0; } static int hal_i2s_master_stream_closed(void) { enum HAL_I2S_ID_T id; for (id = HAL_I2S_ID_0; id < HAL_I2S_ID_QTY; id++) { if (i2s_status[id][AUD_STREAM_PLAYBACK] != HAL_I2S_STATUS_NULL || i2s_status[id][AUD_STREAM_CAPTURE] != HAL_I2S_STATUS_NULL) { if (i2s_mode[id] == HAL_I2S_MODE_MASTER) { return false; } } } return true; } int hal_i2s_open(enum HAL_I2S_ID_T id, enum AUD_STREAM_T stream, enum HAL_I2S_MODE_T mode) { uint32_t reg_base; reg_base = _i2s_get_reg_base(id); ASSERT(mode == HAL_I2S_MODE_MASTER || mode == HAL_I2S_MODE_SLAVE, "Invalid I2S mode for stream %d: %d", stream, mode); ASSERT(i2s_mode[id] == HAL_I2S_MODE_NULL || i2s_mode[id] == mode, "Incompatible I2S mode for stream %d: prev=%d cur=%d", stream, i2s_mode[id], mode); if (i2s_status[id][stream] != HAL_I2S_STATUS_NULL) { TRACE(2, "Invalid I2S opening status for stream %d: %d", stream, i2s_status[id][stream]); return 1; } if (i2s_status[id][AUD_STREAM_PLAYBACK] == HAL_I2S_STATUS_NULL && i2s_status[id][AUD_STREAM_CAPTURE] == HAL_I2S_STATUS_NULL) { if (mode == HAL_I2S_MODE_MASTER) { #ifndef SIMU if (hal_i2s_master_stream_closed()) { analog_aud_pll_open(ANA_AUD_PLL_USER_I2S); } #endif hal_cmu_i2s_clock_enable(id); } if (id == HAL_I2S_ID_0) { hal_iomux_set_i2s0(); #if defined(CHIP_HAS_I2S) && (CHIP_HAS_I2S > 1) } else { hal_iomux_set_i2s1(); #endif } hal_cmu_clock_enable(i2s_mod[id].mod); hal_cmu_clock_enable(i2s_mod[id].apb); hal_cmu_reset_clear(i2s_mod[id].mod); hal_cmu_reset_clear(i2s_mod[id].apb); i2sip_w_enable_i2sip(reg_base, HAL_I2S_YES); for (int i = 0; i < I2S_CHAN_NUM; i++) { i2sip_w_enable_rx_channel(reg_base, i, HAL_I2S_NO); i2sip_w_enable_tx_channel(reg_base, i, HAL_I2S_NO); i2sip_w_rx_fifo_reset(reg_base, i); i2sip_w_tx_fifo_reset(reg_base, i); } #ifndef CHIP_BEST1000 if (mode == HAL_I2S_MODE_MASTER) { i2sip_w_enable_slave_mode(reg_base, HAL_I2S_NO); } else { i2sip_w_enable_slave_mode(reg_base, HAL_I2S_YES); } #endif if (mode == HAL_I2S_MODE_MASTER) { hal_cmu_i2s_set_master_mode(id); } else { hal_cmu_i2s_set_slave_mode(id); } i2s_mode[id] = mode; } i2s_dma[id][stream] = false; i2s_status[id][stream] = HAL_I2S_STATUS_OPENED; return 0; } int hal_i2s_close(enum HAL_I2S_ID_T id, enum AUD_STREAM_T stream) { uint32_t reg_base; reg_base = _i2s_get_reg_base(id); if (i2s_status[id][stream] != HAL_I2S_STATUS_OPENED) { TRACE(2, "Invalid I2S closing status for stream %d: %d", stream, i2s_status[id][stream]); return 1; } i2s_status[id][stream] = HAL_I2S_STATUS_NULL; if (i2s_status[id][AUD_STREAM_PLAYBACK] == HAL_I2S_STATUS_NULL && i2s_status[id][AUD_STREAM_CAPTURE] == HAL_I2S_STATUS_NULL) { i2sip_w_enable_i2sip(reg_base, HAL_I2S_NO); hal_cmu_reset_set(i2s_mod[id].apb); hal_cmu_reset_set(i2s_mod[id].mod); hal_cmu_clock_disable(i2s_mod[id].apb); hal_cmu_clock_disable(i2s_mod[id].mod); if (i2s_mode[id] == HAL_I2S_MODE_MASTER) { hal_cmu_i2s_clock_disable(id); if (hal_i2s_master_stream_closed()) { #if !defined(CHIP_BEST1000) && defined(I2S_MCLK_FROM_SPDIF) hal_cmu_clock_out_disable(); hal_spdif_clock_out_disable(HAL_SPDIF_ID_0); #endif #ifndef SIMU analog_aud_pll_close(ANA_AUD_PLL_USER_I2S); #endif } } i2s_mode[id] = HAL_I2S_MODE_NULL; } return 0; } #ifdef AF_ADC_I2S_SYNC static bool _hal_i2s_enable_delay[HAL_I2S_ID_QTY]; void hal_i2s_enable_delay(enum HAL_I2S_ID_T id) { _hal_i2s_enable_delay[id] = true; } void hal_i2s_disable_delay(enum HAL_I2S_ID_T id) { _hal_i2s_enable_delay[id] = false; } void hal_i2s_enable(enum HAL_I2S_ID_T id) { i2sip_w_enable_clk_gen(_i2s_get_reg_base(id), HAL_I2S_YES); } #endif int hal_i2s_start_stream(enum HAL_I2S_ID_T id, enum AUD_STREAM_T stream) { uint32_t reg_base; uint32_t lock; bool xfer_en[AUD_STREAM_NUM]; reg_base = _i2s_get_reg_base(id); if (i2s_status[id][stream] != HAL_I2S_STATUS_OPENED) { TRACE(2, "Invalid I2S starting status for stream %d: %d", stream, i2s_status[id][stream]); return 1; } if (i2s_mode[id] == HAL_I2S_MODE_SLAVE && sync_start[id][stream]) { xfer_en[stream] = false; xfer_en[!stream] = false; } else { xfer_en[stream] = true; if (i2s_mode[id] == HAL_I2S_MODE_SLAVE && i2s_status[id][!stream] == HAL_I2S_STATUS_STARTED && sync_start[id][!stream]) { xfer_en[!stream] = true; } else { xfer_en[!stream] = false; } } if (stream == AUD_STREAM_PLAYBACK) { lock = int_lock(); i2sip_w_enable_tx_channel(reg_base, 0, HAL_I2S_YES); if (xfer_en[stream]) { i2sip_w_enable_tx_block(reg_base, HAL_I2S_YES); if (i2s_dma[id][stream]) { i2sip_w_enable_tx_dma(reg_base, HAL_I2S_YES); } } if (xfer_en[!stream]) { i2sip_w_enable_rx_block(reg_base, HAL_I2S_YES); } int_unlock(lock); if (i2s_dma[id][stream] && i2s_mode[id] == HAL_I2S_MODE_MASTER) { // Delay a little time for DMA to fill the TX FIFO before sending // (enabling clk gen) for (volatile int i = 0; i < 50; i++) ; } } else { if (i2s_dma[id][stream]) { i2sip_w_enable_rx_dma(reg_base, HAL_I2S_YES); } #ifdef CHIP_BEST2000 int i; for (i = 0; i < I2S_CHAN_NUM; i++) { if (i2s_rx_line_map[id] & (1 << i)) { i2sip_w_enable_rx_channel(reg_base, i, HAL_I2S_YES); } } #else i2sip_w_enable_rx_channel(reg_base, 0, HAL_I2S_YES); #endif lock = int_lock(); if (xfer_en[stream]) { i2sip_w_enable_rx_block(reg_base, HAL_I2S_YES); } if (xfer_en[!stream]) { i2sip_w_enable_tx_block(reg_base, HAL_I2S_YES); if (i2s_dma[id][!stream]) { i2sip_w_enable_tx_dma(reg_base, HAL_I2S_YES); } } int_unlock(lock); } if (i2s_mode[id] == HAL_I2S_MODE_MASTER && !sync_start[id][stream]) { if (i2sip_r_clk_gen_enabled(reg_base) == 0) { hal_cmu_i2s_clock_out_enable(id); #ifdef AF_ADC_I2S_SYNC if (_hal_i2s_enable_delay[id]) { _hal_i2s_enable_delay[id] = false; } else { hal_i2s_enable(id); } #else i2sip_w_enable_clk_gen(reg_base, HAL_I2S_YES); #endif } } i2s_status[id][stream] = HAL_I2S_STATUS_STARTED; return 0; } int hal_i2s_stop_stream(enum HAL_I2S_ID_T id, enum AUD_STREAM_T stream) { uint32_t reg_base; reg_base = _i2s_get_reg_base(id); if (i2s_status[id][stream] != HAL_I2S_STATUS_STARTED) { TRACE(2, "Invalid I2S stopping status for stream %d: %d", stream, i2s_status[id][stream]); return 1; } i2s_status[id][stream] = HAL_I2S_STATUS_OPENED; if (i2s_status[id][AUD_STREAM_PLAYBACK] != HAL_I2S_STATUS_STARTED && i2s_status[id][AUD_STREAM_CAPTURE] != HAL_I2S_STATUS_STARTED) { if (i2s_mode[id] == HAL_I2S_MODE_MASTER) { hal_cmu_i2s_clock_out_disable(id); i2sip_w_enable_clk_gen(reg_base, HAL_I2S_NO); #ifdef AF_ADC_I2S_SYNC _hal_i2s_enable_delay[id] = false; #endif } } if (stream == AUD_STREAM_PLAYBACK) { i2sip_w_enable_tx_block(reg_base, HAL_I2S_NO); i2sip_w_enable_tx_channel(reg_base, 0, HAL_I2S_NO); i2sip_w_enable_tx_dma(reg_base, HAL_I2S_NO); i2sip_w_tx_fifo_reset(reg_base, 0); } else { i2sip_w_enable_rx_block(reg_base, HAL_I2S_NO); i2sip_w_enable_rx_dma(reg_base, HAL_I2S_NO); #ifdef CHIP_BEST1000 i2sip_w_enable_rx_channel(reg_base, 0, HAL_I2S_NO); i2sip_w_rx_fifo_reset(reg_base, 0); #else int i; for (i = 0; i < I2S_CHAN_NUM; i++) { i2sip_w_enable_rx_channel(reg_base, i, HAL_I2S_NO); i2sip_w_rx_fifo_reset(reg_base, i); } #endif } return 0; } int hal_i2s_setup_stream(enum HAL_I2S_ID_T id, enum AUD_STREAM_T stream, const struct HAL_I2S_CONFIG_T *cfg) { uint32_t reg_base; uint32_t div = 0; uint8_t cycles; uint8_t resolution = 0, word_sclk = 0; bool valid; int POSSIBLY_UNUSED i; reg_base = _i2s_get_reg_base(id); if (i2s_status[id][stream] != HAL_I2S_STATUS_OPENED) { TRACE(2, "Invalid I2S setup status for stream %d: %d", stream, i2s_status[id][stream]); return 1; } cycles = cfg->cycles; if (cycles == 0) { if (cfg->bits <= AUD_BITS_16) { cycles = 16; } else { cycles = 32; } } ASSERT(cycles >= cfg->bits, "I2S cycles (%u) should >= bits (%u)", cycles, cfg->bits); switch (cycles) { case 16: word_sclk = I2SIP_CLK_CFG_WSS_VAL_16CYCLE; break; case 24: word_sclk = I2SIP_CLK_CFG_WSS_VAL_24CYCLE; break; case 32: word_sclk = I2SIP_CLK_CFG_WSS_VAL_32CYCLE; break; default: ASSERT(false, "Bad I2S cycles (%u)", cycles); return 1; } switch (cfg->bits) { case AUD_BITS_8: resolution = I2SIP_CFG_WLEN_VAL_IGNORE; break; case AUD_BITS_12: resolution = I2SIP_CFG_WLEN_VAL_12BIT; break; case AUD_BITS_16: resolution = I2SIP_CFG_WLEN_VAL_16BIT; break; case AUD_BITS_20: resolution = I2SIP_CFG_WLEN_VAL_20BIT; break; case AUD_BITS_24: resolution = I2SIP_CFG_WLEN_VAL_24BIT; break; case AUD_BITS_32: resolution = I2SIP_CFG_WLEN_VAL_32BIT; break; default: ASSERT(false, "Bad I2S bits (%u)", cfg->bits); return 1; } /* word clock width : how many sclk work sclk count*/ /* sclk gate in word clock : how many sclk gate : fixed no gate */ i2sip_w_clk_cfg_reg(reg_base, (word_sclk << I2SIP_CLK_CFG_WSS_SHIFT) | (I2SIP_CLK_CFG_SCLK_GATE_VAL_NO_GATE << I2SIP_CLK_CFG_SCLK_GATE_SHIFT)); #ifdef CHIP_BEST2000 if (stream == AUD_STREAM_PLAYBACK) { valid = (cfg->channel_num == AUD_CHANNEL_NUM_2); } else { valid = (cfg->channel_num == AUD_CHANNEL_NUM_2 || cfg->channel_num == AUD_CHANNEL_NUM_4 || cfg->channel_num == AUD_CHANNEL_NUM_6 || cfg->channel_num == AUD_CHANNEL_NUM_8); } #else valid = (cfg->channel_num == AUD_CHANNEL_NUM_2); #endif ASSERT(valid, "[%s] Stream %d Channel number(%d) error", __func__, stream, cfg->channel_num); if (i2s_mode[id] == HAL_I2S_MODE_MASTER) { uint32_t i2s_clock; uint32_t bit_rate; for (i = 0; i < ARRAY_SIZE(i2s_sample_rate); i++) { if (i2s_sample_rate[i].sample_rate == cfg->sample_rate) { break; } } ASSERT(i < ARRAY_SIZE(i2s_sample_rate), "%s: Invalid i2s sample rate: %d", __func__, cfg->sample_rate); TRACE(3, "[%s] stream=%d sample_rate=%d", __func__, stream, cfg->sample_rate); ASSERT(i2s_sample_rate[i].codec_div / i2s_sample_rate[i].cmu_div * i2s_sample_rate[i].cmu_div == i2s_sample_rate[i].codec_div, "%s: Invalid codec div for rate %u: codec_div=%u cmu_div=%u", __func__, cfg->sample_rate, i2s_sample_rate[i].codec_div, i2s_sample_rate[i].cmu_div); #ifndef SIMU analog_aud_freq_pll_config(i2s_sample_rate[i].codec_freq, i2s_sample_rate[i].codec_div); #ifdef CHIP_BEST2000 analog_aud_pll_set_dig_div(i2s_sample_rate[i].codec_div / i2s_sample_rate[i].cmu_div); #endif #endif i2s_clock = i2s_sample_rate[i].codec_freq * i2s_sample_rate[i].cmu_div; bit_rate = i2s_sample_rate[i].sample_rate * AUD_CHANNEL_NUM_2 * cycles; div = i2s_clock / bit_rate; ASSERT( i2s_clock == bit_rate * div, "%s: Bad stream cfg (bad cycles?): i2s_clock=%u bit_rate=%u cycles=%u", __func__, i2s_clock, bit_rate, cycles); #if !defined(CHIP_BEST1000) && defined(I2S_MCLK_FROM_SPDIF) #ifdef I2S_MCLK_PIN hal_iomux_set_i2s_mclk(); hal_cmu_i2s_mclk_enable(HAL_CMU_I2S_MCLK_PLLSPDIF0); #else hal_iomux_set_clock_out(); hal_cmu_clock_out_enable(HAL_CMU_CLOCK_OUT_MCU_SPDIF0); #endif // By default MCLK is half of (CODEC_FREQ_24P576M or CODEC_FREQ_22P5792M) hal_spdif_clock_out_enable(HAL_SPDIF_ID_0, i2s_sample_rate[i].cmu_div * I2S_MCLK_DIV); #endif hal_cmu_i2s_set_div(id, div); } if ((stream == AUD_STREAM_PLAYBACK && i2s_status[id][AUD_STREAM_CAPTURE] == HAL_I2S_STATUS_NULL) || (stream == AUD_STREAM_CAPTURE && i2s_status[id][AUD_STREAM_PLAYBACK] == HAL_I2S_STATUS_NULL)) { hal_cmu_reset_pulse(i2s_mod[id].mod); } i2s_dma[id][stream] = cfg->use_dma; sync_start[id][stream] = cfg->sync_start; if (stream == AUD_STREAM_PLAYBACK) { /* resolution : valid bit width */ i2sip_w_tx_resolution(reg_base, 0, resolution); /* fifo level to trigger empty interrupt or dma req */ i2sip_w_tx_fifo_threshold(reg_base, 0, HAL_I2S_TX_FIFO_TRIGGER_LEVEL); } else { #ifdef CHIP_BEST2000 uint32_t ch; uint32_t cnt = 0; i2s_rx_line_map[id] = 0; for (i = 0; i < I2S_CHAN_NUM; i++) { ch = (cfg->channel_map >> (i * 2)) & 3; ASSERT(ch == 0 || ch == 3, "[%s] Stream %d Bad Chan Map 0x%04X", __func__, stream, cfg->channel_map); if (ch == 3) { i2s_rx_line_map[id] |= (1 << i); cnt += 2; } } ASSERT(cnt == cfg->channel_num, "[%s] Stream %d Unmatched Chan Num (%u) and Map (0x%04X)", __func__, stream, cfg->channel_num, cfg->channel_map); if (cfg->chan_sep_buf) { i2sip_w_rx_dma_blk_size(reg_base, HAL_I2S_RX_FIFO_TRIGGER_LEVEL); i2sp_w_enable_rx_dma_block(reg_base, HAL_I2S_YES); } else { i2sp_w_enable_rx_dma_block(reg_base, HAL_I2S_NO); } for (i = 0; i < I2S_CHAN_NUM; i++) { if (i2s_rx_line_map[id] & (1 << i)) { i2sip_w_rx_resolution(reg_base, i, resolution); i2sip_w_rx_fifo_threshold(reg_base, i, HAL_I2S_RX_FIFO_TRIGGER_LEVEL); } } #else /* resolution : valid bit width */ i2sip_w_rx_resolution(reg_base, 0, resolution); /* fifo level to trigger empty interrupt or dma req */ i2sip_w_rx_fifo_threshold(reg_base, 0, HAL_I2S_RX_FIFO_TRIGGER_LEVEL); #endif } return 0; } int hal_i2s_send(enum HAL_I2S_ID_T id, const uint8_t *value, uint32_t value_len) { uint32_t i = 0; uint32_t reg_base; reg_base = _i2s_get_reg_base(id); for (i = 0; i < value_len; i += 4) { while (!(i2sip_r_int_status(reg_base, 0) & I2SIP_INT_STATUS_TX_FIFO_EMPTY_MASK)) ; i2sip_w_tx_left_fifo(reg_base, 0, value[i + 1] << 8 | value[i]); i2sip_w_tx_right_fifo(reg_base, 0, value[i + 3] << 8 | value[i + 2]); } return 0; } uint8_t hal_i2s_recv(enum HAL_I2S_ID_T id, uint8_t *value, uint32_t value_len) { // uint32_t reg_base; // reg_base = _i2s_get_reg_base(id); return 0; } //================================================================================ // I2S Packet Mode //================================================================================ static bool i2s_pkt_opened = false; int hal_i2s_packet_open(void) { uint32_t reg_base; uint8_t resolution = 0, word_sclk = 0; if (i2s_pkt_opened) { return 1; } word_sclk = I2SIP_CLK_CFG_WSS_VAL_32CYCLE; resolution = I2SIP_CFG_WLEN_VAL_32BIT; reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); hal_iomux_set_i2s0(); hal_cmu_i2s_clock_enable(HAL_I2S_ID_0); hal_cmu_clock_enable(i2s_mod[HAL_I2S_ID_0].mod); hal_cmu_clock_enable(i2s_mod[HAL_I2S_ID_0].apb); hal_cmu_reset_clear(i2s_mod[HAL_I2S_ID_0].mod); hal_cmu_reset_clear(i2s_mod[HAL_I2S_ID_0].apb); i2sip_w_enable_i2sip(reg_base, HAL_I2S_YES); for (int i = 0; i < I2S_CHAN_NUM; i++) { i2sip_w_enable_rx_channel(reg_base, i, HAL_I2S_NO); i2sip_w_enable_tx_channel(reg_base, i, HAL_I2S_NO); } hal_cmu_i2s_set_slave_mode(HAL_I2S_ID_0); #ifndef CHIP_BEST1000 i2sip_w_enable_slave_mode(reg_base, HAL_I2S_YES); #endif /* word clock width : how many sclk work sclk count*/ /* sclk gate in word clock : how many sclk gate : fixed no gate */ i2sip_w_clk_cfg_reg(reg_base, (word_sclk << I2SIP_CLK_CFG_WSS_SHIFT) | (I2SIP_CLK_CFG_SCLK_GATE_VAL_NO_GATE << I2SIP_CLK_CFG_SCLK_GATE_SHIFT)); i2sip_w_tx_resolution(reg_base, 0, resolution); i2sip_w_tx_fifo_threshold(reg_base, 0, HAL_I2S_TX_FIFO_TRIGGER_LEVEL); i2sip_w_rx_resolution(reg_base, 0, resolution); i2sip_w_rx_fifo_threshold(reg_base, 0, HAL_I2S_RX_FIFO_TRIGGER_LEVEL); i2s_pkt_opened = true; return 0; } int hal_i2s_packet_close(void) { uint32_t reg_base; if (!i2s_pkt_opened) { return 1; } reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_enable_i2sip(reg_base, HAL_I2S_NO); hal_cmu_reset_set(i2s_mod[HAL_I2S_ID_0].apb); hal_cmu_reset_set(i2s_mod[HAL_I2S_ID_0].mod); hal_cmu_clock_disable(i2s_mod[HAL_I2S_ID_0].apb); hal_cmu_clock_disable(i2s_mod[HAL_I2S_ID_0].mod); hal_cmu_i2s_clock_disable(HAL_I2S_ID_0); i2s_pkt_opened = false; return 0; } int hal_i2s_start_transfer(void) { uint32_t reg_base; if (!i2s_pkt_opened) { return 1; } hal_cmu_reset_pulse(i2s_mod[HAL_I2S_ID_0].mod); reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_enable_tx_channel(reg_base, 0, HAL_I2S_YES); i2sip_w_enable_tx_dma(reg_base, HAL_I2S_YES); i2sip_w_enable_tx_block(reg_base, HAL_I2S_YES); i2sip_w_enable_rx_channel(reg_base, 0, HAL_I2S_YES); i2sip_w_enable_rx_dma(reg_base, HAL_I2S_YES); i2sip_w_enable_rx_block(reg_base, HAL_I2S_YES); return 0; } int hal_i2s_stop_transfer(void) { uint32_t reg_base; if (!i2s_pkt_opened) { return 1; } reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_enable_tx_block(reg_base, HAL_I2S_NO); i2sip_w_enable_tx_channel(reg_base, 0, HAL_I2S_NO); i2sip_w_enable_tx_dma(reg_base, HAL_I2S_NO); i2sip_w_tx_fifo_reset(reg_base, 0); i2sip_w_enable_rx_block(reg_base, HAL_I2S_NO); i2sip_w_enable_rx_channel(reg_base, 0, HAL_I2S_NO); i2sip_w_enable_rx_dma(reg_base, HAL_I2S_NO); i2sip_w_rx_fifo_reset(reg_base, 0); return 0; } void hal_i2s_tx_sync_enable(enum HAL_I2S_SYNC_TYPE_T type) { uint32_t reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_tx_sync_enable(reg_base, type); } void hal_i2s_tx_sync_disable(void) { uint32_t reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_tx_sync_disable(reg_base); } void hal_i2s_rx_sync_enable(enum HAL_I2S_SYNC_TYPE_T type) { uint32_t reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_rx_sync_enable(reg_base, type); } void hal_i2s_rx_sync_disable(void) { uint32_t reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_rx_sync_disable(reg_base); } void hal_i2s_clk_sync_enable(enum HAL_I2S_SYNC_TYPE_T type) { uint32_t reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_clk_sync_enable(reg_base, type); } void hal_i2s_clk_sync_disable(void) { uint32_t reg_base = _i2s_get_reg_base(HAL_I2S_ID_0); i2sip_w_clk_sync_disable(reg_base); }