#include "xc_drv_codec.h" #include "xc_drv_dma.h" #include "string.h" #include "ringbuffer.h" #if XC_CHECK(XC_CODEC_ENABLED) #define CONFIG_ENABLE_DMA #define AON_RF_AONREG ((volatile unsigned *)0x40002430) #define RF_ANA02 ((volatile unsigned *)(0X4002F000+ 0x008)) #define RF_ANA03 ((volatile unsigned *)(0X4002F000+ 0x00C)) #define RF_ANA08 ((volatile unsigned *)(0X4002F000+ 0x020)) #define RF_ANA15 ((volatile unsigned *)(0X4002F000+ 0x03C)) #define RF_ANA21 ((volatile unsigned *)(0X4002F000+ 0x054)) #define RF_ANA26 ((volatile unsigned *)(0X4002F000+ 0x068)) #define RF_ANA27 ((volatile unsigned *)(0X4002F000+ 0x06C)) #define RF_ANA28 ((volatile unsigned *)(0X4002F000+ 0x070)) #define RF_ANA29 ((volatile unsigned *)(0X4002F000+ 0x074)) #define DMAS_BASE 0x50001000 #define DMAS_CHx_SAR(a) ((volatile unsigned *)(DMAS_BASE + 0x40 + ((a) * 0x20))) #define DMAS_CHx_DAR(a) ((volatile unsigned *)(DMAS_BASE + 0x44 + ((a) * 0x20))) #define DMAS_CHx_CTL0(a) ((volatile unsigned *)(DMAS_BASE + 0x48 + ((a) * 0x20))) #define DMAS_CHx_CTL1(a) ((volatile unsigned *)(DMAS_BASE + 0x4C + ((a) * 0x20))) #define DMAS_CHx_CA(a) ((volatile unsigned *)(DMAS_BASE + 0x50 + ((a) * 0x20))) #define DMAS_INT_EN0 ((volatile unsigned *)(DMAS_BASE + 0x10)) codec_finish_callback_t finish_callback; void xc_codec_dac_digital_enable(void) { cdc_ana_reg2__endac__setf(ENABLE); } void xc_codec_dac_digital_disable(void) { cdc_ana_reg2__endac__setf(DISABLE); } void xc_codec_dac_analog_enable(void) { cdc_ana_reg0__pdbias__setf(0); // PDL=0, PDPAL=0 cdc_ana_reg3__pdl__setf(PDL_RST); for(int i=0;i<5000;i++){__NOP();}; cdc_ana_reg3__pdpal__setf(PDPAL_RST); for(int i=0;i<5000;i++){__NOP();}; } void xc_codec_dac_analog_disable(void) { cdc_ana_reg3__pdl__setf(1); for(int i=0;i<5000;i++){__NOP();}; cdc_ana_reg3__pdpal__setf(1); for(int i=0;i<5000;i++){__NOP();}; cdc_ana_reg0__pdvbias__setf(1); cdc_ana_reg0__pdbias__setf(1); cdc_ana_reg0__pdmic__setf(1); cdc_ana_reg0__pdsto__setf(1); cdc_ana_reg0__pdpgal__setf(1); cdc_ana_reg0__pdpgar__setf(1); cdc_ana_reg0__pdsdml__setf(1); cdc_ana_reg0__pdsdmr__setf(1); } void xc_codec_dac_disable(void) { xc_codec_dac_analog_disable(); xc_codec_dac_digital_disable(); } void xc_codec_dac_enable(void) { xc_codec_dac_analog_enable(); xc_codec_dac_digital_enable(); } // 0x1F:max volume, -2dB step (0x00:+6dB) void xc_codec_dac_analog_gain_set(uint8_t leftgain, uint8_t rightgain) { cdc_ana_reg1__dacavl__setf(leftgain); for(int i=0;i<10;i++){__NOP();}; cdc_ana_reg1__dacavr__setf(rightgain); for(int i=0;i<10;i++){__NOP();}; } // 0x80:max volume, 1/128 step void xc_codec_dac_digital_gain_set(uint8_t leftgain, uint8_t rightgain) { cdc_ana_reg2__dacvoll__setf(leftgain); cdc_ana_reg2__dacvolr__setf(rightgain); } void codec_irq_enable(uint32_t irq) { uint32_t val = cdc_int_en_get(); val |= irq; cdc_int_en_set(val); } void codec_irq_disable(uint32_t irq) { uint32_t val = cdc_int_en_get(); val &= ~irq; cdc_int_en_set(val); } void xc_codec_dma_enable(uint32_t sta) { uint32_t val = cdc_dma_config_get(); val |= sta; cdc_dma_config_set(val); } void xc_codec_dma_disable(uint32_t sta) { uint32_t val = cdc_dma_config_get(); val &= ~sta; cdc_dma_config_set(val); } void xc_codec_dac_blk_finish_cb_register(codec_finish_callback callback) { finish_callback.codec_dac_trans_finish_callback = callback; } void xc_codec_adc_blk_finish_cb_register(codec_finish_callback callback) { finish_callback.codec_adc_receive_finish_callback = callback; } void xc_codec_select_none_integer_clk_div(uint32_t div) { uint32_t val; __read_hw_reg32(CDC_ANA_REG6,val); if (div) val |= (0x40 << 16); __write_hw_reg32(CDC_ANA_REG6,val); for(int i=0;i<5000;i++){__NOP();}; } static void xc_codec_set_dac_dn(uint32_t dn_val) { uint32_t val; __read_hw_reg32(CDC_ANA_REG7,val); val &= 0xFFFF00FF; val |= ((dn_val & 0xFF) << 8); __write_hw_reg32(CDC_ANA_REG7, val); for(int i=0;i<5000;i++){__NOP();}; if (dn_val & 0xFF00) { __read_hw_reg32(CDC_ANA_REG6,val); val |= (4 << 16); __write_hw_reg32(CDC_ANA_REG6,val); } for(int i=0;i<5000;i++){__NOP();}; } static void xc_codec_set_dac_dm(uint32_t dn_val) { uint32_t val; __read_hw_reg32(CDC_ANA_REG7,val); val &= 0xFF00FFFF; val |= ((dn_val & 0xFF) << 16); __write_hw_reg32(CDC_ANA_REG7, val); for(int i=0;i<5000;i++){__NOP();}; if (dn_val & 0xFF00) { __read_hw_reg32(CDC_ANA_REG6,val); val |= (8 << 16); __write_hw_reg32(CDC_ANA_REG6,val); } for(int i=0;i<5000;i++){__NOP();}; } static void xc_codec_set_adc_dn(uint32_t dn_val) { uint32_t val; __read_hw_reg32(CDC_ANA_REG6,val); val &= 0x00FFFFFF; val |= ((dn_val & 0xFF) << 24); __write_hw_reg32(CDC_ANA_REG6, val); for(int i=0;i<5000;i++){__NOP();}; if (dn_val & 0xFF00) { __read_hw_reg32(CDC_ANA_REG6,val); val |= (1 << 16); __write_hw_reg32(CDC_ANA_REG6,val); } for(int i=0;i<5000;i++){__NOP();}; } static void xc_codec_set_adc_dm(uint32_t dm_val) { uint32_t val; __read_hw_reg32(CDC_ANA_REG7,val); val &= 0xFFFFFF00; val |= dm_val & 0xFF; __write_hw_reg32(CDC_ANA_REG7, val); for(int i=0;i<5000;i++){__NOP();}; if (dm_val & 0xFF00) { __read_hw_reg32(CDC_ANA_REG6,val); val |= (2 << 16); __write_hw_reg32(CDC_ANA_REG6,val); } for(int i=0;i<5000;i++){__NOP();}; } static int xc_codec_mclk_12m_set_lrck(Codec_SampleRate_e lr_clk, uint8_t type) { uint32_t dn_val,dm_val; if (lr_clk >= LRCK_96KHZ) { return -1; } switch (lr_clk) { case LRCK_48KHZ: dm_val = 61; dn_val = 64; break; case LRCK_32KHZ: dm_val = 247; dn_val = 128; break; case LRCK_24KHZ: dm_val = 93; dn_val = 32; break; case LRCK_16KHZ: dm_val = 311; dn_val = 64; break; case LRCK_12KHZ: dm_val = 109; dn_val = 16; break; case LRCK_8KHZ: dm_val = 343; dn_val = 32; break; case LRCK_44_1KHZ: dm_val = 9; dn_val = 8; break; case LRCK_22_05KHZ: dm_val = 13; dn_val = 4; break; case LRCK_11_025KHZ: dm_val = 15; dn_val = 2; break; default: return -1; } if (type == 1) { xc_codec_set_dac_dn(dn_val); xc_codec_set_dac_dm(dm_val); } else { xc_codec_set_adc_dn(dn_val); xc_codec_set_adc_dm(dm_val); } return 0; } int xc_codec_mclk_13m_set_lrck(Codec_SampleRate_e lr_clk, uint8_t type) { uint32_t dn_val, dm_val; if (lr_clk > LRCK_96KHZ) { return -1; } switch (lr_clk) { case LRCK_96KHZ: dm_val = 256; dn_val = 15; break; case LRCK_48KHZ: dm_val = 128; dn_val = 143; break; case LRCK_32KHZ: dm_val = 64; dn_val = 139; break; case LRCK_24KHZ: dm_val = 64; dn_val = 207; break; case LRCK_16KHZ: dm_val = 32; dn_val = 171; break; case LRCK_12KHZ: dm_val = 32; dn_val = 239; break; case LRCK_8KHZ: dm_val = 16; dn_val = 187; break; case LRCK_44_1KHZ: dm_val = 128; dn_val = 167; break; case LRCK_22_05KHZ: dm_val = 64; dn_val = 231; break; case LRCK_11_025KHZ: dm_val = 32; dn_val = 263; break; default: return -1; } if (type == 1) { xc_codec_set_dac_dn(dn_val); xc_codec_set_dac_dm(dm_val); } else { xc_codec_set_adc_dn(dn_val); xc_codec_set_adc_dm(dm_val); } return 0; } void xc_codec_set_pga_gain(Mic_PGA_Gain_e gain) { uint32_t val; __read_hw_reg32(CDC_ANA_REG0,val); val &= 0xFFEFFFFF; val |= gain << 20; __write_hw_reg32(CDC_ANA_REG0, val); for(int i=0;i<5000;i++){__NOP();}; } void xc_codec_set_adc_gain(ADC_Analog_Vol_e r_gain) { uint32_t val; __read_hw_reg32(CDC_ANA_REG0,val); val &= 0xFFFF00FF; val |= r_gain << 8; __write_hw_reg32(CDC_ANA_REG0, val); for(int i=0;i<5000;i++){__NOP();}; } static int codec_clk_enable(Codec_clk_e clk) { uint8_t cdcclk, cdcmul = 1, cdcdiv = 1; CLOCK_HFCLK_In_Typedef hf_clk = xc_clock_hfclk_in_get(); cpr_ctlapbclken_grctl__bt_pclk_en__setf(ENABLE);/* bt_pclk */ cprao_aon_coreldo_en__bb_corerfldo_en__setf(ENABLE); /* open rf digital */ cpr_rf_reg1__cdc_rstn_reg__setf(RSTN_VALID); /* reset audio adc */ cpr_rf_reg1__cdc_rstn_reg__setf(RSTN_INVALID); //audio ADC mclk primary frequency division set 2[FPGA no active] if (clk == CODEC_MCLK_12M) { if (hf_clk == CLOCK_HFCLK_IN_16M) { cdcclk = 4; } else if (hf_clk == CLOCK_HFCLK_IN_24M) { #if (CONFIG_HFCLK_IS_OSC24M_PLL_24M) cdcclk = 4; #else cdcclk = 4; #endif } else if (hf_clk == CLOCK_HFCLK_IN_32M) { cdcclk = 2; } else if (hf_clk == CLOCK_HFCLK_IN_48M) { cdcclk = 4; } else if (hf_clk == CLOCK_HFCLK_IN_64M) { cdcclk = 1; } else if (hf_clk == CLOCK_HFCLK_IN_96M) { cdcclk = 2; } else { return -1; } } else { return -1; } cpr_rf_reg1__cdc_mclk_gr__setf(cdcclk); cpr_rf_reg2_pack(cdcmul, cdcdiv); /* cdc mclk_mul mclk_div set */ cpr_rf_reg1__cdc_mclk_gr_upd__setf(ENABLE); cpr_rf_reg1__cdc_hclk_en__setf(ENABLE); for(int i=0;i<10;i++){__NOP();}; cdc_ana_reg6__sel_noni__setf(1); /* Select None-integer clock divider */ return 0; } void codec_clk_disable(uint8_t clk) { cpr_rf_reg1__cdc_hclk_en__setf(DISABLE); cprao_aon_coreldo_en__bb_corerfldo_en__setf(DISABLE); cpr_ctlapbclken_grctl__bt_pclk_en__setf(DISABLE); } static void codec_adc_analog_enable(void) { cdc_ana_reg0__pdvbias__setf(1); __NOP();__NOP(); cdc_ana_reg0__pdbias__setf(0); __NOP();__NOP(); cdc_ana_reg0__pdmic__setf(0); __NOP();__NOP(); cdc_ana_reg0__pdsto__setf(0); __NOP();__NOP(); cdc_ana_reg0__pdpgal__setf(1); __NOP();__NOP(); cdc_ana_reg0__pdpgar__setf(0); __NOP();__NOP(); cdc_ana_reg0__pdsdml__setf(1); __NOP();__NOP(); cdc_ana_reg0__pdsdmr__setf(0); __NOP();__NOP(); } static void codec_adc_dma_init(uint32_t daraddr, uint32_t transfsize) { DMA_Chx_Cfg_t ch_cfg = { .sar = (uint32_t)0x50004020, .dar = daraddr, .ctl_src_msize = DMA_MSIZE_1, .ctl_dst_msize = DMA_MSIZE_1, .ctl_sinc = DMA_ADDR_NOCHANGE, .ctl_dinc = DMA_ADDR_INCREMENT, .ctl_src_tr_width = DMA_TRANS_WIDTH_32, .ctl_dst_tr_width = DMA_TRANS_WIDTH_32, .ctl_block_ts = transfsize, .ctl_tt_fc = DMA_PRF2MEM_DMA, .cfg_hs_sel_src = DMA_HS_HARDWARE, .cfg_hs_sel_dst = DMA_HS_HARDWARE, .cfg_fifo_mode = DMA_FIFO_MODE_SINGLE, .cfg_src_per = CDC_DMA_RX_HS_IF13, }; cdc_dma_config__dma_rx_en__setf(1); xc_dma_init(); xc_dma_set_channel_config(CODEC_ADC_DMA_CHANNEL, &ch_cfg); xc_dma_set_listener(CODEC_ADC_DMA_CHANNEL, NULL); } void xc_codec_adc_init(codec_adc_config_t *cfg) { codec_clk_enable(cfg->codec_clk); xc_codec_mclk_12m_set_lrck(cfg->sampleRate, 0); cdc_ana_reg0__adinsell__setf(2); __NOP();__NOP(); cdc_ana_reg0__adinselr__setf(2); __NOP();__NOP(); cdc_ana_reg0__adcvoll__setf(cfg->analog_vol_l); cdc_ana_reg0__adcvolr__setf(cfg->analog_vol_r); __NOP();__NOP(); cdc_ana_reg0__vbctrl_l__setf(1); __NOP();__NOP(); cdc_ana_reg0__micsel__setf(MIC1); __NOP();__NOP(); cdc_ana_reg0__micgain__setf(cfg->mic_pga_gain); __NOP();__NOP(); cdc_ana_reg0__stogain__setf(cfg->sto_pga_gain); //Sidetone PGA Gain Control __NOP();__NOP(); cdc_ana_reg1__enhpf__setf(0); __NOP();__NOP(); cdc_ana_reg1__hpfbypass__setf(1); __NOP();__NOP(); cdc_ana_reg4__acdc_vol__setf(cfg->digital_vol); __NOP();__NOP(); codec_adc_analog_enable(); cdc_dma_config__dma_rxlvl__setf(CODEC_ADC_FIFO_LEN); cdc_fifo_status__rxfifo_flush__setf(1); for(int i=0;i<20;i++){__NOP();}; cdc_fifo_status__rxfifo_flush__setf(0); __NOP();__NOP(); cdc_ana_reg1__hpfbypass__setf(1); #ifdef USE_DMA codec_adc_dma_init((uint32_t)cfg->voice_buffer,cfg->transf_size); #endif } void xc_codec_adc_start(void* cb) { #ifndef USE_DMA xc_codec_adc_blk_finish_cb_register((codec_finish_callback)cb); codec_irq_enable(RXFIFO_UNDERFLOW_EN | RXFIFO_OVERFLOW_EN | RXFIFO_DATA_READY_EN); NVIC_EnableIRQ(CDC_IRQn); #else NVIC_EnableIRQ(DMA_IRQn); xc_dma_enable(); uint8_t ret = xc_dma_start_transfer(CODEC_ADC_DMA_CHANNEL, (DMA_Callback)cb); if (ret != 0) { DEBUG("\nERROR: Failed to begin the interrupt transfer\n"); } #endif // flush RX FIFO cdc_fifo_status__rxfifo_flush__setf(1); for(int i=0;i<20;i++){__NOP();}; cdc_fifo_status__rxfifo_flush__setf(0); __NOP();__NOP(); cdc_ana_reg1__hpfbypass__setf(1); //Enable ADC if (cdc_ana_reg1__enadc__getf() == DISABLE) { cdc_ana_reg1__enadc__setf(ENABLE); } } void xc_codec_adc_stop(void) { // flush RX FIFO cdc_fifo_status__rxfifo_flush__setf(1); for(int i=0;i<20;i++){__NOP();}; cdc_fifo_status__rxfifo_flush__setf(0); #ifndef USE_DMA NVIC_DisableIRQ(CDC_IRQn); #else NVIC_DisableIRQ(DMA_IRQn); // xc_dma_disable(); #endif xc_codec_dac_disable(); } static void codec_dac_dma_init(uint32_t saraddr, uint32_t transfsize) { DMA_Chx_Cfg_t ch_cfg = { .sar = saraddr, .dar = (uint32_t)0x50004038, .ctl_src_msize = DMA_MSIZE_8, .ctl_dst_msize = DMA_MSIZE_8, .ctl_sinc = DMA_ADDR_INCREMENT, .ctl_dinc = DMA_ADDR_NOCHANGE, .ctl_src_tr_width = DMA_TRANS_WIDTH_32, .ctl_dst_tr_width = DMA_TRANS_WIDTH_32, .ctl_block_ts = transfsize, .ctl_tt_fc = DMA_MEM2PRF_DMA, .cfg_hs_sel_src = DMA_HS_HARDWARE, .cfg_hs_sel_dst = DMA_HS_HARDWARE, .cfg_fifo_mode = DMA_FIFO_MODE_SINGLE, .cfg_dst_per = CDC_DMA_TX_HS_IF6, }; cdc_dma_config__dma_tx_en__setf(1); xc_dma_init(); xc_dma_set_channel_config(CODEC_DAC_DMA_CHANNEL, &ch_cfg); xc_dma_set_listener(CODEC_DAC_DMA_CHANNEL, NULL); } void xc_codec_dac_init(codec_dac_config_t *cfg) { if (cpr_rf_reg1__cdc_hclk_en__getf() == DISABLE) { codec_clk_enable(cfg->codec_clk); } cdc_ana_reg2__dacmono__setf(cfg->mono_mode); __NOP(); xc_codec_mclk_12m_set_lrck(cfg->sampleRate, 1); if (cfg->sampleRate >= LRCK_44_1KHZ) { cdc_ana_reg6__filt_sel__setf((uint8_t)(cfg->sampleRate - LRCK_44_1KHZ)); } else { cdc_ana_reg6__filt_sel__setf((uint8_t)RATE_OTHERS); } // reg14 bit 0:from i2s,1: from ahb bus cdc_ana_reg5__dac_data_sel__setf(1); if (cfg->digital_vol_l > 0x80) { cfg->digital_vol_l = 0x80; } if (cfg->digital_vol_r > 0x80) { cfg->digital_vol_r = 0x80; } if (cfg->analog_vol_l > DAC_ANALOG_VOL_MUTE) { cfg->analog_vol_l = DAC_ANALOG_VOL_MUTE; } // dac digital volume set xc_codec_dac_digital_gain_set(cfg->digital_vol_l, cfg->digital_vol_r); // dac analog volume set xc_codec_dac_analog_gain_set(cfg->analog_vol_l, cfg->analog_vol_r); // cdc_ana_reg2__ictrl__setf(1); cdc_dma_config__dma_txlvl__setf(CODEC_DAC_FIFO_LEN); #ifdef USE_DMA codec_dac_dma_init((uint32_t)cfg->voice_buffer,cfg->transf_size); #endif } void xc_codec_dac_start(void* cb) { #ifndef USE_DMA xc_codec_dac_blk_finish_cb_register((codec_finish_callback)cb); codec_irq_enable(TXFIFO_UNDERFLOW_EN | TXFIFO_OVERFLOW_EN | TXFIFO_DATA_READY_EN); NVIC_EnableIRQ(CDC_IRQn); #else NVIC_EnableIRQ(DMA_IRQn); xc_dma_enable(); uint8_t ret = xc_dma_start_transfer(CODEC_DAC_DMA_CHANNEL, (DMA_Callback)cb); if (ret != 0) { DEBUG("\nERROR: Failed to begin the interrupt transfer\n"); } #endif // flush TX FIFO cdc_fifo_status__txfifo_flush__setf(1); for(int i=0;i<20;i++){__NOP();}; cdc_fifo_status__txfifo_flush__setf(0); //Enable DAC xc_codec_dac_enable(); if (cdc_ana_reg1__enadc__getf() == DISABLE) { cdc_ana_reg1__enadc__setf(ENABLE); } } void xc_codec_dac_stop(void) { // flush TX FIFO cdc_fifo_status__txfifo_flush__setf(1); for(int i=0;i<20;i++){__NOP();}; cdc_fifo_status__txfifo_flush__setf(0); #ifndef USE_DMA NVIC_DisableIRQ(CDC_IRQn); #else NVIC_DisableIRQ(DMA_IRQn); // xc_dma_disable(); #endif xc_codec_dac_disable(); } void CDC_Handler() { uint32_t val = cdc_int_get(); if (val & TXFIFO_UNDERFLOW_EN) { if (finish_callback.codec_dac_trans_finish_callback != NULL) { finish_callback.codec_dac_trans_finish_callback(TXFIFO_UNDERFLOW_EN); } } if (val & TXFIFO_OVERFLOW_EN) { if (finish_callback.codec_dac_trans_finish_callback != NULL) { finish_callback.codec_dac_trans_finish_callback(TXFIFO_OVERFLOW_EN); } } if (val & TXFIFO_DATA_READY_EN) { if (finish_callback.codec_dac_trans_finish_callback != NULL) { finish_callback.codec_dac_trans_finish_callback(TXFIFO_DATA_READY_EN); } } if (val & RXFIFO_UNDERFLOW_EN) { if (finish_callback.codec_adc_receive_finish_callback != NULL) { finish_callback.codec_adc_receive_finish_callback(RXFIFO_UNDERFLOW_EN); } } if (val & RXFIFO_OVERFLOW_EN) { if (finish_callback.codec_adc_receive_finish_callback != NULL) { finish_callback.codec_adc_receive_finish_callback(RXFIFO_OVERFLOW_EN); } } if (val & RXFIFO_DATA_READY_EN) { if (finish_callback.codec_adc_receive_finish_callback != NULL) { finish_callback.codec_adc_receive_finish_callback(RXFIFO_DATA_READY_EN); } } cdc_int_set(val); } #endif // XC_CHECK(XC_CODEC_ENABLED)