#include #include #include #include #ifdef RT_USING_FINSH #include #endif #include "board.h" #include "dma.h" #ifdef RT_USING_ICODEC #include "drv_gpio.h" #include "drv_clock.h" #include "drv_aic.h" #include "drv_aic_i2s.h" #include "drv_codec_icodec.h" #define CODEC_DEBUG 0 #if CODEC_DEBUG #define CODEC_DBG(...) rt_kprintf("[CODEC]"),rt_kprintf(__VA_ARGS__) #else #define CODEC_DBG(...) #endif /* * Sampling rate */ const int sample_attr[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000, }; static uint8_t _g_icodec_reg_defcache[SCODA_MAX_REG_NUM] = { #if 1 /* reg 0x0 ... 0x9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03, /* reg 0xa ... 0x13 */ 0x00,0x40,0x30,0x80,0x01,0x00,0x00,0x00,0x0f,0x40, /* reg 0x14 ... 0x1d */ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff, /* reg 0x1e ... 0x27 */ 0x00,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* reg 0x28 ... 0x31 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* reg 0x32 ... 0x39 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* extern reg */ 0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x34,0x07,0x44,0x1f,0x00, #else /* reg 0x0 ... 0x9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03, /* reg 0xa ... 0x13 */ 0x00,0x00,0x30,0xb0,0x01,0x00,0x00,0x00,0x0F,0x40, /* reg 0x14 ... 0x1d */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff, /* reg 0x1e ... 0x27 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* reg 0x28 ... 0x31 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* reg 0x32 ... 0x39 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* extern reg */ 0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x34,0x07,0x44,0x1f,0x00, #endif }; static int jz_icodec_reg_volatile(uint32_t reg) { if (reg > SCODA_MAX_REG_NUM) return 1; switch (reg) { case SCODA_REG_SR: case SCODA_REG_SR2: case SCODA_REG_SIGR: case SCODA_REG_SIGR3: case SCODA_REG_SIGR5: case SCODA_REG_SIGR7: case SCODA_REG_MR: case SCODA_REG_IFR: case SCODA_REG_IFR2: case SCODA_REG_SR_ADC_AGCDGL: case SCODA_REG_SR_ADC_AGCDGR: case SCODA_REG_SR_ADC_AGCAGL: case SCODA_REG_SR_ADC_AGCAGR: case SCODA_REG_SR_TR1: case SCODA_REG_SR_TR2: case SCODA_REG_SR_TR_SRCDAC: return 1; default: return 0; } } static int jz_icodec_reg_writable(uint32_t reg) { if (reg > SCODA_MAX_REG_NUM) return 0; switch (reg) { case SCODA_REG_SR: case SCODA_REG_SR2: case SCODA_REG_SIGR: case SCODA_REG_SIGR3: case SCODA_REG_SIGR5: case SCODA_REG_SIGR7: case SCODA_REG_MR: case SCODA_REG_SR_ADC_AGCDGL: case SCODA_REG_SR_ADC_AGCDGR: case SCODA_REG_SR_ADC_AGCAGL: case SCODA_REG_SR_ADC_AGCAGR: case SCODA_REG_SR_TR1: case SCODA_REG_SR_TR2: case SCODA_REG_SR_TR_SRCDAC: return 0; default: return 1; } } static int jz_icodec_reg_readable(uint32_t reg) { if (reg > SCODA_MAX_REG_NUM) return 0; else return 1; } static uint8_t jz_icodec_reg_read(struct jz_icodec *icodec, uint32_t reg) { int ret = 0; uint8_t val = 0; if (!jz_icodec_reg_volatile(reg)) { val = icodec_hw_read(icodec, reg); if ((reg == SCODA_REG_GCR_DACL) || (reg == SCODA_REG_GCR_DACR)) { if (val < 32) val = 31 - val; else val = 95 - val; } return val; } if (jz_icodec_reg_readable(reg)) return icodec_hw_read(icodec, reg); return 0; } static int jz_icodec_reg_write(struct jz_icodec *codec, uint16_t reg, int value) { int ret = 0; int val = value; if (jz_icodec_reg_writable(reg)) { if (!jz_icodec_reg_volatile(reg)) { if((reg == SCODA_REG_GCR_DACL)||(reg == SCODA_REG_GCR_DACR)) { if(val < 32) val = 31 - val; else val = 95 - val; } _g_icodec_reg_defcache[reg] = val; } return icodec_hw_write(codec, reg, val); } return 0; } static int jz_icodec_reg_update_bits(struct jz_icodec *icodec, uint16_t reg, uint32_t mask, uint16_t value) { uint8_t change; uint8_t old, new; int ret; ret = jz_icodec_reg_read(icodec, reg); if (ret < 0) return ret; old = ret; new = (old & ~mask) | (value & mask); change = old != new; if (change) ret = jz_icodec_reg_write(icodec, reg, new); if (ret < 0) return ret; return change; } static int jz_icodec_set_sampling_rate(struct jz_icodec *icodec, int rate) { /* sampling rate */ int speed_sel = 0; if(rate == icodec->replay_config.samplerate) return rate; /* set sampling rate */ for (speed_sel = 0; rate > sample_attr[speed_sel]; speed_sel++) ; jz_icodec_reg_update_bits(icodec, SCODA_REG_FCR_DAC, SCODA_FCR_FREQ_MASK, (speed_sel << SCODA_FCR_FREQ_SHIFT)); jz_icodec_reg_update_bits(icodec, SCODA_REG_FCR_ADC, SCODA_FCR_FREQ_MASK, (speed_sel << SCODA_FCR_FREQ_SHIFT)); rate = sample_attr[speed_sel]; icodec->replay_config.samplerate = rate; return rate; } static void jz_icodec_hw_params(struct jz_icodec* icodec,int stream) { int playback = (stream == AUDIO_STREAM_REPLAY); int speed_sel = 0; int bit_width_sel = 3; int aicr_reg = playback ? SCODA_REG_AICR_DAC : SCODA_REG_AICR_ADC; int fcr_reg = playback ? SCODA_REG_FCR_DAC : SCODA_REG_FCR_ADC; /* bit width */ switch (icodec->replay_config.samplefmt) { case AUDIO_FMT_PCM_S16_LE: bit_width_sel = 0; break; case AUDIO_FMT_PCM_S24_LE: bit_width_sel = 3; break; } /*sample rate*/ for (speed_sel = 0; icodec->replay_config.samplerate > sample_attr[speed_sel]; speed_sel++); jz_icodec_reg_update_bits(icodec, aicr_reg, SCODA_AICR_DAC_ADWL_MASK,(bit_width_sel << SCODA_AICR_DAC_ADWL_SHIFT)); jz_icodec_reg_update_bits(icodec, fcr_reg, SCODA_FCR_FREQ_MASK,(speed_sel << SCODA_FCR_FREQ_SHIFT)); } static int jz_icodec_digital_mute(struct jz_icodec *icodec, int mute) { jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_DAC, SCODA_CR_DAC_SMUTE_MASK, (!!mute) << SCODA_CR_DAC_SMUTE_SHIFT); jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_SMUTE_MASK, (!!mute) << SCODA_CR_ADC_SMUTE_SHIFT); return 0; } static void jz_icodec_startup(struct jz_icodec *icodec) { /*power on codec*/ if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 0)) rt_thread_delay(rt_tick_from_millisecond(250)); if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 0)) rt_thread_delay(rt_tick_from_millisecond(400)); } static void jz_icodec_shutdown(struct jz_icodec *icodec) { /*power off codec*/ jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 1); jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 1); } static void jz_icodec_mute_stream(struct jz_icodec *icodec, int mute, int stream) { if(stream == AUDIO_STREAM_REPLAY) { jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_DAC, SCODA_CR_DAC_SMUTE_MASK, (!!mute) << SCODA_CR_DAC_SMUTE_SHIFT); } else if(stream == AUDIO_STREAM_RECORD) { jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_SMUTE_MASK, (!!mute) << SCODA_CR_ADC_SMUTE_SHIFT); } } #define VOLUME_MIN 0 #define VOLUME_MAX 100 #define REPLAY_REG_MAX (63) static int jz_icodec_set_replay_volume(struct jz_icodec *icodec,int val) { int phyValue = 0; /* get current volume */ if (val < VOLUME_MIN) val = VOLUME_MIN; else if(val >= VOLUME_MAX) val = VOLUME_MAX; phyValue = (val* REPLAY_REG_MAX) / VOLUME_MAX; CODEC_DBG("volume = %d\n",val); jz_icodec_reg_write(icodec,SCODA_REG_GCR_DACL,phyValue); jz_icodec_reg_write(icodec,SCODA_REG_GCR_DACR,phyValue); icodec->user_replay_volume = jz_icodec_reg_read(icodec,SCODA_REG_GCR_DACL); if (val == 0) { jz_icodec_digital_mute(icodec,1); } else { jz_icodec_digital_mute(icodec,0); } return val; } #define REPLAY_MIXER_REG_MAX 31 int jz_icodec_set_replay_mixer_volume(struct jz_icodec *icodec,int val) { int phyValue = 0; /* get current volume */ if (val < VOLUME_MIN) val = VOLUME_MIN; else if(val >= VOLUME_MAX) val = VOLUME_MAX; phyValue = (val * REPLAY_MIXER_REG_MAX) / VOLUME_MAX; jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXDACL,phyValue); jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXDACR,phyValue); return val; } #define DIGITAL_CAP_REG_MAX 43 int jz_icodec_set_digital_capture_volume(struct jz_icodec *icodec,int val) { int phyValue = 0; /* get current volume */ if (val < VOLUME_MIN) val = VOLUME_MIN; else if(val >= VOLUME_MAX) val = VOLUME_MAX; phyValue = (val * DIGITAL_CAP_REG_MAX) / VOLUME_MAX; jz_icodec_reg_write(icodec,SCODA_REG_GCR_ADCL,phyValue); jz_icodec_reg_write(icodec,SCODA_REG_GCR_ADCR,phyValue); return val; } #define DIGITAL_CAP_MIX_REG_MAX 31 int jz_icodec_set_digital_capture_mixer_volume(struct jz_icodec *icodec,int val) { int phyValue = 0; /* get current volume */ if (val < VOLUME_MIN) val = VOLUME_MIN; else if(val >= VOLUME_MAX) val = VOLUME_MAX; phyValue = (val * DIGITAL_CAP_MIX_REG_MAX) / VOLUME_MAX; jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXADCL,phyValue); jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIXADCR,phyValue); return val; } #define MIC_REG_MAX 4 int aic_icodec_set_mic_volume(struct jz_icodec *icodec,int val) { int phyValue = 0; /* get current volume */ if (val < VOLUME_MIN) val = VOLUME_MIN; else if(val >= VOLUME_MAX) val = VOLUME_MAX; phyValue = MIC_REG_MAX - (val) * MIC_REG_MAX / VOLUME_MAX; jz_icodec_reg_write(icodec,SCODA_REG_GCR_MIC1,phyValue); return val; } enum { AMIC_ON = 0, DMIC_ON = 1, }; void jz_icodec_adc_mic_select(struct jz_icodec *icodec, int dmic) { if(dmic == DMIC_ON) { jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_MIC_SEL_MASK, (1 << SCODA_CR_ADC_MIC_SEL_SHIFT)); } else { jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_ADC, SCODA_CR_ADC_MIC_SEL_MASK, (0 << SCODA_CR_ADC_MIC_SEL_SHIFT)); } } void jz_icodec_adc_capture_enable(struct jz_icodec *icodec,int enable) { if(enable) { jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_SB_MASK, (0 << SCODA_AICR_ADC_SB_SHIFT)); } else { jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_SB_MASK, (1 << SCODA_AICR_ADC_SB_SHIFT)); } } /********************************************************************************************************* ** Audio device *********************************************************************************************************/ static rt_err_t icodec_getcaps (struct rt_audio_device *audio,struct rt_audio_caps *caps) { rt_err_t result = RT_EOK; struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; CODEC_DBG("type = %d\n",caps->main_type); switch (caps->main_type) { case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */ { switch (caps->sub_type) { case AUDIO_TYPE_QUERY: caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; break; default: result = -RT_ERROR; break; } break; } case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */ switch (caps->sub_type) { case AUDIO_DSP_PARAM: if (audio->replay == NULL) { result = -RT_ERROR; break; } caps->udata.config.channels = icodec->replay_config.channels; caps->udata.config.samplefmt = icodec->replay_config.samplefmt; caps->udata.config.samplerate = icodec->replay_config.samplerate; caps->udata.config.samplefmts = icodec->replay_config.samplefmts; break; default: result = -RT_ERROR; break; } break; case AUDIO_TYPE_MIXER: /* report the Mixer Units */ switch (caps->sub_type) { case AUDIO_MIXER_QUERY: caps->udata.mask = AUDIO_MIXER_VOLUME | AUDIO_MIXER_DIGITAL | AUDIO_MIXER_LINE; break; case AUDIO_MIXER_VOLUME: caps->udata.value = icodec->user_replay_volume; break; case AUDIO_MIXER_DIGITAL: break; case AUDIO_MIXER_LINE: break; default: result = -RT_ERROR; break; } break; default: result = -RT_ERROR; break; } return result; } static rt_err_t icodec_configure (struct rt_audio_device *audio,struct rt_audio_caps *caps) { rt_err_t result = RT_EOK; struct jz_icodec *icodec = (struct jz_icodec *) audio->parent.user_data; CODEC_DBG("type = %d\n",caps->main_type); switch (caps->main_type) { case AUDIO_TYPE_MIXER: switch (caps->sub_type) { case AUDIO_MIXER_VOLUME: { int volume = caps->udata.value; jz_icodec_set_replay_volume(icodec, volume); } break; case AUDIO_MIXER_DIGITAL: { int gain = caps->udata.value; jz_icodec_set_replay_mixer_volume(icodec, gain); } break; case AUDIO_MIXER_LINE: { int gain = caps->udata.value; //set linein valume... } break; case AUDIO_MIXER_EXTEND: break; default: result = -RT_ERROR; break; } break; case AUDIO_TYPE_OUTPUT: { switch (caps->sub_type) { case AUDIO_DSP_PARAM: { CODEC_DBG(" AUDIO_TYPE_OUTPUT:\n");CODEC_DBG(" Number of channels: %u\n", caps->udata.config.channels);CODEC_DBG(" Sample rate: %u\n", caps->udata.config.samplerate);CODEC_DBG(" Sample format: %u\n", caps->udata.config.samplefmt); //upgrate codec chip icodec->i2s->channels = caps->udata.config.channels; icodec->i2s->rates = caps->udata.config.samplerate; icodec->i2s->fmt_width = rt_audio_format_to_bits(caps->udata.config.samplefmt); aic_i2s_hw_params(icodec->i2s, AUDIO_STREAM_REPLAY); aic_i2s_set_sysclk(icodec->i2s, icodec->i2s->rates); //save config icodec->replay_config.channels = caps->udata.config.channels; icodec->replay_config.samplefmt = caps->udata.config.samplefmt; icodec->replay_config.samplerate = caps->udata.config.samplerate; icodec->replay_config.samplefmts = caps->udata.config.samplefmts; break; } case AUDIO_DSP_SAMPLERATE: { int rate = caps->udata.value; jz_icodec_set_sampling_rate(icodec, rate); break; } default: result = -RT_ERROR; break; } } break; default: result = -RT_ERROR; break; } return result; } static rt_err_t icodec_init (struct rt_audio_device *audio) { struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; uint16_t i; /* disable shutdown */ gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,AUDIO_SHUTDOWN_MUTE); rt_thread_delay(RT_TICK_PER_SECOND / 4); gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,!AUDIO_SHUTDOWN_MUTE); rt_thread_delay(RT_TICK_PER_SECOND / 4); /* write default value ... */ for (i = 0; i < sizeof(_g_icodec_reg_defcache); ++i) { jz_icodec_reg_write(icodec, i, _g_icodec_reg_defcache[i]); } /* power off codec */ jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 1); jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 1); /* codec select enable 24M clock*/ jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_CK , SCODA_CR_CK_MCLK_DIV_MASK, 1 << SCODA_CR_CK_MCLK_DIV_SHIFT); jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_CK , SCODA_CR_CK_SDCLK_MASK, 0 << SCODA_CR_CK_SDCLK_SHIFT); jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_CK , SCODA_CR_CRYSTAL_MASK, 0 << SCODA_CR_CRYSTAL_SHIFT); /*codec select Dac/Adc i2s interface*/ jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_SLAVE_MASK, 0); jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_AUDIO_MASK, SCODA_AICR_DAC_AUDIOIF_I2S); jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_AUDIO_MASK, 0); jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_AUDIO_MASK, SCODA_AICR_ADC_AUDIOIF_I2S); /*codec generated IRQ is a high level */ jz_icodec_reg_update_bits(icodec, SCODA_REG_ICR, SCODA_ICR_INT_FORM_MASK, SCODA_ICR_INT_FORM_LOW); /*codec irq mask*/ jz_icodec_reg_write(icodec, SCODA_REG_IMR, SCODA_IMR_COMMON_MASK); jz_icodec_reg_write(icodec, SCODA_REG_IMR2, SCODA_IMR2_COMMON_MASK); /*codec clear all irq*/ jz_icodec_reg_write(icodec, SCODA_REG_IFR, SCODA_IMR_COMMON_MASK); jz_icodec_reg_write(icodec, SCODA_REG_IFR2, SCODA_IMR2_COMMON_MASK); /* PCM Format */ #if (ICODEC_PCM_FORMAT == AUDIO_FMT_PCM_S16_LE) jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_DAC, SCODA_AICR_DAC_ADWL_MASK, (0 << SCODA_AICR_DAC_ADWL_SHIFT)); jz_icodec_reg_update_bits(icodec, SCODA_REG_AICR_ADC, SCODA_AICR_ADC_ADWL_MASK, (0 << SCODA_AICR_ADC_ADWL_SHIFT)); #endif /* sampling rate */ jz_icodec_set_sampling_rate(icodec,ICODEC_SAMPLING_RATE); /*power on codec*/ jz_icodec_digital_mute(icodec,0); if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_MASK, 0)) rt_thread_delay(rt_tick_from_millisecond(250)); if (jz_icodec_reg_update_bits(icodec, SCODA_REG_CR_VIC, SCODA_CR_VIC_SB_SLEEP_MASK, 0)) rt_thread_delay(rt_tick_from_millisecond(400)); return RT_EOK; } static rt_err_t icodec_shutdown (struct rt_audio_device *audio) { struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; #ifdef AUDIO_SHUTDOWN_PORT gpio_set_value(AUDIO_SHUTDOWN_PORT,AUDIO_SHUTDOWN_PIN,AUDIO_SHUTDOWN_MUTE); #endif return RT_EOK; } rt_err_t icodec_start (struct rt_audio_device *audio,int stream) { struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_START,stream); return RT_EOK; } rt_err_t icodec_stop (struct rt_audio_device *audio,int stream) { struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_STOP,stream); return RT_EOK; } static rt_err_t icodec_suspend (struct rt_audio_device *audio,int stream) { struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_SUSPEND,stream); return RT_EOK; } static rt_err_t icodec_resume (struct rt_audio_device *audio,int stream) { struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; aic_i2s_trigger(icodec->i2s,I2S_TRIGGER_RESUME,stream); return RT_EOK; } static rt_err_t icodec_control (struct rt_audio_device *audio, int cmd, void *args) { rt_err_t result = RT_EOK; struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; switch (cmd) { case AUDIO_CTL_HWRESET: break; case AUDIO_CTL_GETBUFFERINFO: { struct rt_audio_buf_info *info = (struct rt_audio_buf_info *)args; if(info != RT_NULL) { info->buffer_count = CFG_I2S_DMA_PAGE_NUM; info->buffer_size = CFG_I2S_DMA_PAGE_SIZE; } } break; default: result = -RT_ERROR; break; } return result; } static void codec_write_complete(void *data, void *pbuf) { struct rt_audio_device *audio = (struct rt_audio_device *)data; /* notify transmitted complete. */ rt_audio_tx_complete(audio,pbuf); } static rt_size_t icodec_transmit (struct rt_audio_device *audio,const void *writeBuf,void *readBuf, rt_size_t size) { struct jz_icodec *icodec = (struct jz_icodec *)audio->parent.user_data; CODEC_DBG("writeBuf = %x,readBuf=%x,size=%d\n",(rt_uint32_t)writeBuf,(rt_uint32_t)readBuf,size); if(writeBuf != RT_NULL) { return aic_i2s_send(icodec->i2s, writeBuf, size, codec_write_complete, (void *)audio); } return 0; } static struct jz_icodec _g_jz_icodec = { .mapped_base = AIC_BASE + 0xA0, .user_replay_volume = 31, }; static struct rt_audio_device _g_audio_device; const struct rt_audio_ops _g_audio_ops = { .getcaps = icodec_getcaps, .configure = icodec_configure, .init = icodec_init, .shutdown = icodec_shutdown, .start = icodec_start, .stop = icodec_stop, .suspend = icodec_suspend , .resume = icodec_resume , .control = icodec_control, .transmit = icodec_transmit, }; int rt_hw_codec_init(void) { int result; struct rt_audio_device *audio = &_g_audio_device; struct jz_icodec *icodec = &_g_jz_icodec; struct jz_i2s *i2s; rt_kprintf("init i2s....\n"); i2s = rt_hw_aic_i2s_init(); if(i2s == RT_NULL) { CODEC_DBG("i2s device not found!\r\n"); return -RT_EIO; } icodec->i2s = i2s; #ifdef AUDIO_DEVICE_USE_PRIVATE_BUFFER { rt_uint8_t *mempool = (rt_uint8_t *)rt_malloc(CODEC_MP_SZ); if(mempool == RT_NULL) { CODEC_DBG("no memory...\n"); return -RT_ENOMEM; } rt_mp_init(&icodec->mp,"codecbuf",mempool,CODEC_MP_SZ,CODEC_MP_BLOCK_SZ); } #endif /* AUDIO_DEVICE_USE_PRIVATE_BUFFER */ //init default configuration { icodec->replay_config.channels = 2; icodec->replay_config.samplefmt = AUDIO_FMT_PCM_S16_LE; icodec->replay_config.samplerate = 44100; icodec->replay_config.samplefmts = AUDIO_FMT_PCM_S16_LE; } audio->ops = (struct rt_audio_ops *)&_g_audio_ops; result = rt_audio_register(audio,"sound0",RT_DEVICE_FLAG_WRONLY,icodec); if(result != RT_EOK) { CODEC_DBG("icodec device register error..\n"); return result; } rt_kprintf("codec initialization done!\n"); return RT_EOK; } INIT_DEVICE_EXPORT(rt_hw_codec_init); #endif /* RT_USING_ICODEC */