/* * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include "es8374_codec.h" #include "esp_log.h" #include "esp_codec_dev_vol.h" #include "es_common.h" #define TAG "ES8374" typedef struct { audio_codec_if_t base; es8374_codec_cfg_t cfg; bool is_open; bool enabled; } audio_codec_es8374_t; static const esp_codec_dev_vol_range_t vol_range = { .min_vol = { .vol = 0xC0, .db_value = -96.0, }, .max_vol = { .vol = 0x0, .db_value = 0.0, }, }; static int es8374_write_reg(audio_codec_es8374_t *codec, int reg, int value) { return codec->cfg.ctrl_if->write_reg(codec->cfg.ctrl_if, reg, 1, &value, 1); } static int es8374_read_reg(audio_codec_es8374_t *codec, int reg, int *value) { *value = 0; return codec->cfg.ctrl_if->read_reg(codec->cfg.ctrl_if, reg, 1, value, 1); } static int es8374_set_voice_mute(audio_codec_es8374_t *codec, bool enable) { int ret = 0; int reg = 0; ret |= es8374_read_reg(codec, 0x36, ®); if (ret == 0) { reg = reg & 0xdf; ret |= es8374_write_reg(codec, 0x36, reg | (((int) enable) << 5)); } return ret; } static es_bits_length_t get_bits(uint8_t bits) { switch (bits) { default: case 16: return BIT_LENGTH_16BITS; case 18: return BIT_LENGTH_18BITS; case 20: return BIT_LENGTH_20BITS; case 24: return BIT_LENGTH_24BITS; case 32: return BIT_LENGTH_32BITS; } } static int es8374_set_bits_per_sample(audio_codec_es8374_t *codec, uint8_t bits) { int ret = ESP_CODEC_DEV_OK; int reg = 0; es_bits_length_t bit_per_sample = get_bits(bits); bits = (int) bit_per_sample & 0x0f; if (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_ADC) { ret |= es8374_read_reg(codec, 0x10, ®); if (ret == 0) { reg = reg & 0xe3; ret |= es8374_write_reg(codec, 0x10, reg | (bits << 2)); } } if (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_DAC) { ret |= es8374_read_reg(codec, 0x11, ®); if (ret == 0) { reg = reg & 0xe3; ret |= es8374_write_reg(codec, 0x11, reg | (bits << 2)); } } return ret; } static int _set_mic_gain(audio_codec_es8374_t *codec, float gain) { int ret = 0; if (gain >= 0 && gain < 24) { int gain_n = 0; gain_n = (int) gain / 3; ret = es8374_write_reg(codec, 0x22, gain_n | (gain_n << 4)); // MIC PGA } else { ret = -1; } return ret; } static int es8374_i2s_config_clock(audio_codec_es8374_t *codec, es_i2s_clock_t cfg) { int ret = 0; int reg = 0; ret |= es8374_read_reg(codec, 0x0f, ®); // power up adc and input reg &= 0xe0; int divratio = 0; switch (cfg.sclk_div) { case MCLK_DIV_1: divratio = 1; break; case MCLK_DIV_2: // = 2, divratio = 2; break; case MCLK_DIV_3: // = 3, divratio = 3; break; case MCLK_DIV_4: // = 4, divratio = 4; break; case MCLK_DIV_5: // = 20, divratio = 5; break; case MCLK_DIV_6: // = 5, divratio = 6; break; case MCLK_DIV_7: // = 29, divratio = 7; break; case MCLK_DIV_8: // = 6, divratio = 8; break; case MCLK_DIV_9: // = 7, divratio = 9; break; case MCLK_DIV_10: // = 21, divratio = 10; break; case MCLK_DIV_11: // = 8, divratio = 11; break; case MCLK_DIV_12: // = 9, divratio = 12; break; case MCLK_DIV_13: // = 30, divratio = 13; break; case MCLK_DIV_14: // = 31 divratio = 14; break; case MCLK_DIV_15: // = 22, divratio = 15; break; case MCLK_DIV_16: // = 10, divratio = 16; break; case MCLK_DIV_17: // = 23, divratio = 17; break; case MCLK_DIV_18: // = 11, divratio = 18; break; case MCLK_DIV_20: // = 24, divratio = 19; break; case MCLK_DIV_22: // = 12, divratio = 20; break; case MCLK_DIV_24: // = 13, divratio = 21; break; case MCLK_DIV_25: // = 25, divratio = 22; break; case MCLK_DIV_30: // = 26, divratio = 23; break; case MCLK_DIV_32: // = 27, divratio = 24; break; case MCLK_DIV_33: // = 14, divratio = 25; break; case MCLK_DIV_34: // = 28, divratio = 26; break; case MCLK_DIV_36: // = 15, divratio = 27; break; case MCLK_DIV_44: // = 16, divratio = 28; break; case MCLK_DIV_48: // = 17, divratio = 29; break; case MCLK_DIV_66: // = 18, divratio = 30; break; case MCLK_DIV_72: // = 19, divratio = 31; break; default: break; } reg |= divratio; ret |= es8374_write_reg(codec, 0x0f, reg); int dacratio_l = 0; int dacratio_h = 0; switch (cfg.lclk_div) { case LCLK_DIV_128: dacratio_l = 128 % 256; dacratio_h = 128 / 256; break; case LCLK_DIV_192: dacratio_l = 192 % 256; dacratio_h = 192 / 256; break; case LCLK_DIV_256: dacratio_l = 256 % 256; dacratio_h = 256 / 256; break; case LCLK_DIV_384: dacratio_l = 384 % 256; dacratio_h = 384 / 256; break; case LCLK_DIV_512: dacratio_l = 512 % 256; dacratio_h = 512 / 256; break; case LCLK_DIV_576: dacratio_l = 576 % 256; dacratio_h = 576 / 256; break; case LCLK_DIV_768: dacratio_l = 768 % 256; dacratio_h = 768 / 256; break; case LCLK_DIV_1024: dacratio_l = 1024 % 256; dacratio_h = 1024 / 256; break; case LCLK_DIV_1152: dacratio_l = 1152 % 256; dacratio_h = 1152 / 256; break; case LCLK_DIV_1408: dacratio_l = 1408 % 256; dacratio_h = 1408 / 256; break; case LCLK_DIV_1536: dacratio_l = 1536 % 256; dacratio_h = 1536 / 256; break; case LCLK_DIV_2112: dacratio_l = 2112 % 256; dacratio_h = 2112 / 256; break; case LCLK_DIV_2304: dacratio_l = 2304 % 256; dacratio_h = 2304 / 256; break; case LCLK_DIV_125: dacratio_l = 125 % 256; dacratio_h = 125 / 256; break; case LCLK_DIV_136: dacratio_l = 136 % 256; dacratio_h = 136 / 256; break; case LCLK_DIV_250: dacratio_l = 250 % 256; dacratio_h = 250 / 256; break; case LCLK_DIV_272: dacratio_l = 272 % 256; dacratio_h = 272 / 256; break; case LCLK_DIV_375: dacratio_l = 375 % 256; dacratio_h = 375 / 256; break; case LCLK_DIV_500: dacratio_l = 500 % 256; dacratio_h = 500 / 256; break; case LCLK_DIV_544: dacratio_l = 544 % 256; dacratio_h = 544 / 256; break; case LCLK_DIV_750: dacratio_l = 750 % 256; dacratio_h = 750 / 256; break; case LCLK_DIV_1000: dacratio_l = 1000 % 256; dacratio_h = 1000 / 256; break; case LCLK_DIV_1088: dacratio_l = 1088 % 256; dacratio_h = 1088 / 256; break; case LCLK_DIV_1496: dacratio_l = 1496 % 256; dacratio_h = 1496 / 256; break; case LCLK_DIV_1500: dacratio_l = 1500 % 256; dacratio_h = 1500 / 256; break; default: break; } ret |= es8374_write_reg(codec, 0x06, dacratio_h); // ADCFsMode,singel SPEED,RATIO=256 ret |= es8374_write_reg(codec, 0x07, dacratio_l); // ADCFsMode,singel SPEED,RATIO=256 return ret; } static int es8374_set_d2se_pga(audio_codec_es8374_t *codec, es_d2se_pga_t gain) { int ret = 0; int reg = 0; if (gain > D2SE_PGA_GAIN_MIN && gain < D2SE_PGA_GAIN_MAX) { ret = es8374_read_reg(codec, 0x21, ®); reg &= 0xfb; reg |= gain << 2; ret = es8374_write_reg(codec, 0x21, reg); // MIC PGA } return ret; } static int es8374_config_fmt(audio_codec_es8374_t *codec, es_i2s_fmt_t fmt) { int ret = 0; int reg = 0; int fmt_i2s = fmt & 0x0f; if (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_ADC) { ret |= es8374_read_reg(codec, 0x10, ®); if (ret == 0) { reg = reg & 0xfc; ret |= es8374_write_reg(codec, 0x10, reg | fmt_i2s); } } if (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_DAC) { ret |= es8374_read_reg(codec, 0x11, ®); if (ret == 0) { reg = reg & 0xfc; ret |= es8374_write_reg(codec, 0x11, reg | (fmt_i2s)); } } return ret; } static int es8374_config_dac_output(audio_codec_es8374_t *codec, es_dac_output_t output) { int ret = 0; int reg = 0; ret = es8374_write_reg(codec, 0x1d, 0x02); ret |= es8374_read_reg(codec, 0x1c, ®); // set spk mixer reg |= 0x80; ret |= es8374_write_reg(codec, 0x1c, reg); ret |= es8374_write_reg(codec, 0x1D, 0x02); // spk set ret |= es8374_write_reg(codec, 0x1F, 0x00); // spk set ret |= es8374_write_reg(codec, 0x1E, 0xA0); // spk on return ret; } static int es8374_config_adc_input(audio_codec_es8374_t *codec, es_adc_input_t input) { int ret = 0; int reg = 0; ret |= es8374_read_reg(codec, 0x21, ®); if (ret == 0) { reg = (reg & 0xcf) | 0x14; ret |= es8374_write_reg(codec, 0x21, reg); } return ret; } static int es8374_set_adc_dac_volume(audio_codec_es8374_t *codec, esp_codec_dec_work_mode_t mode, float db_value) { int reg = esp_codec_dev_vol_calc_reg(&vol_range, db_value); int ret = ESP_CODEC_DEV_OK; if (mode & ESP_CODEC_DEV_WORK_MODE_ADC) { ret = es8374_write_reg(codec, 0x25, (uint8_t) reg); } if (mode & ESP_CODEC_DEV_WORK_MODE_DAC) { ret = es8374_write_reg(codec, 0x38, (uint8_t) reg); } return ret; } static int es8374_init_reg(audio_codec_es8374_t *codec, es_i2s_fmt_t fmt, es_i2s_clock_t cfg, es_dac_output_t out_channel, es_adc_input_t in_channel) { int ret = 0; int reg = 0; ret |= es8374_write_reg(codec, 0x00, 0x3F); // IC Rst start ret |= es8374_write_reg(codec, 0x00, 0x03); // IC Rst stop ret |= es8374_write_reg(codec, 0x01, 0x7F); // IC clk on ret |= es8374_read_reg(codec, 0x0F, ®); reg &= 0x7f; reg |= (codec->cfg.master_mode << 7); ret |= es8374_write_reg(codec, 0x0f, reg); // CODEC IN I2S SLAVE MODE ret |= es8374_write_reg(codec, 0x6F, 0xA0); // pll set:mode enable ret |= es8374_write_reg(codec, 0x72, 0x41); // pll set:mode set ret |= es8374_write_reg(codec, 0x09, 0x01); // pll set:reset on ,set start ret |= es8374_write_reg(codec, 0x0C, 0x22); // pll set:k ret |= es8374_write_reg(codec, 0x0D, 0x2E); // pll set:k ret |= es8374_write_reg(codec, 0x0E, 0xC6); // pll set:k ret |= es8374_write_reg(codec, 0x0A, 0x3A); // pll set: ret |= es8374_write_reg(codec, 0x0B, 0x07); // pll set:n ret |= es8374_write_reg(codec, 0x09, 0x41); // pll set:reset off ,set stop ret |= es8374_i2s_config_clock(codec, cfg); ret |= es8374_write_reg(codec, 0x24, 0x08); // adc set ret |= es8374_write_reg(codec, 0x36, 0x00); // dac set ret |= es8374_write_reg(codec, 0x12, 0x30); // timming set ret |= es8374_write_reg(codec, 0x13, 0x20); // timming set ret |= es8374_config_fmt(codec, fmt); ret |= es8374_write_reg(codec, 0x21, 0x50); // adc set: SEL LIN1 CH+PGAGAIN=0DB ret |= es8374_write_reg(codec, 0x22, 0xFF); // adc set: PGA GAIN=0DB ret |= es8374_write_reg(codec, 0x21, 0x14); // adc set: SEL LIN1 CH+PGAGAIN=18DB ret |= es8374_write_reg(codec, 0x22, 0x55); // pga = +15db ret |= es8374_write_reg(codec, 0x08, 0x21); // set class d divider = 33, to avoid the high frequency tone on laudspeaker ret |= es8374_write_reg(codec, 0x00, 0x80); // IC START ret |= es8374_set_adc_dac_volume(codec, ESP_CODEC_DEV_WORK_MODE_ADC, 0.0); // 0db ret |= es8374_write_reg(codec, 0x14, 0x8A); // IC START ret |= es8374_write_reg(codec, 0x15, 0x40); // IC START ret |= es8374_write_reg(codec, 0x1A, 0xA0); // monoout set ret |= es8374_write_reg(codec, 0x1B, 0x19); // monoout set ret |= es8374_write_reg(codec, 0x1C, 0x90); // spk set ret |= es8374_write_reg(codec, 0x1D, 0x01); // spk set ret |= es8374_write_reg(codec, 0x1F, 0x00); // spk set ret |= es8374_write_reg(codec, 0x1E, 0x20); // spk on ret |= es8374_write_reg(codec, 0x28, 0x00); // alc set ret |= es8374_write_reg(codec, 0x25, 0x00); // ADCVOLUME on ret |= es8374_write_reg(codec, 0x38, 0x00); // DACVOLUME on ret |= es8374_write_reg(codec, 0x37, 0x30); // dac set ret |= es8374_write_reg(codec, 0x6D, 0x60); // SEL:GPIO1=DMIC CLK OUT+SEL:GPIO2=PLL CLK OUT ret |= es8374_write_reg(codec, 0x71, 0x05); // for automute setting ret |= es8374_write_reg(codec, 0x73, 0x70); ret |= es8374_config_dac_output(codec, out_channel); // 0x3c Enable DAC and Enable Lout/Rout/1/2 ret |= es8374_config_adc_input(codec, in_channel); // 0x00 LINSEL & RINSEL ret |= es8374_set_adc_dac_volume(codec, ESP_CODEC_DEV_WORK_MODE_DAC, -96.0); ret |= es8374_write_reg(codec, 0x37, 0x00); // dac set return ret; } static int es8374_stop(audio_codec_es8374_t *codec) { int ret = 0; int reg = 0; if (codec->cfg.codec_mode == ESP_CODEC_DEV_WORK_MODE_LINE) { ret |= es8374_read_reg(codec, 0x1a, ®); // disable lout reg |= 0x08; ret |= es8374_write_reg(codec, 0x1a, reg); reg &= 0x9f; ret |= es8374_write_reg(codec, 0x1a, reg); ret |= es8374_write_reg(codec, 0x1D, 0x12); // mute speaker ret |= es8374_write_reg(codec, 0x1E, 0x20); // disable class d ret |= es8374_read_reg(codec, 0x1c, ®); // disable spkmixer reg &= 0xbf; ret |= es8374_write_reg(codec, 0x1c, reg); ret |= es8374_write_reg(codec, 0x1F, 0x00); // spk set } if (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_DAC) { ret |= es8374_set_voice_mute(codec, true); ret |= es8374_read_reg(codec, 0x1a, ®); // disable lout reg |= 0x08; ret |= es8374_write_reg(codec, 0x1a, reg); reg &= 0xdf; ret |= es8374_write_reg(codec, 0x1a, reg); ret |= es8374_write_reg(codec, 0x1D, 0x12); // mute speaker ret |= es8374_write_reg(codec, 0x1E, 0x20); // disable class d ret |= es8374_read_reg(codec, 0x15, ®); // power up dac reg |= 0x20; ret |= es8374_write_reg(codec, 0x15, reg); } if (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_ADC) { ret |= es8374_read_reg(codec, 0x10, ®); // power up adc and input reg |= 0xc0; ret |= es8374_write_reg(codec, 0x10, reg); ret |= es8374_read_reg(codec, 0x21, ®); // power up adc and input reg |= 0xc0; ret |= es8374_write_reg(codec, 0x21, reg); } return ret; } static int es8374_start(audio_codec_es8374_t *codec) { int ret = ESP_CODEC_DEV_OK; int reg = 0; bool mode_line = (codec->cfg.codec_mode == ESP_CODEC_DEV_WORK_MODE_LINE); if (mode_line) { ret |= es8374_read_reg(codec, 0x1a, ®); // set monomixer reg |= 0x60; reg |= 0x20; reg &= 0xf7; ret |= es8374_write_reg(codec, 0x1a, reg); ret |= es8374_read_reg(codec, 0x1c, ®); // set spk mixer reg |= 0x40; ret |= es8374_write_reg(codec, 0x1c, reg); ret |= es8374_write_reg(codec, 0x1D, 0x02); // spk set ret |= es8374_write_reg(codec, 0x1F, 0x00); // spk set ret |= es8374_write_reg(codec, 0x1E, 0xA0); // spk on } if (mode_line || (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_ADC)) { ret |= es8374_read_reg(codec, 0x21, ®); // power up adc and input reg &= 0x3f; ret |= es8374_write_reg(codec, 0x21, reg); ret |= es8374_read_reg(codec, 0x10, ®); // power up adc and input reg &= 0x3f; ret |= es8374_write_reg(codec, 0x10, reg); } if (mode_line || (codec->cfg.codec_mode & ESP_CODEC_DEV_WORK_MODE_DAC)) { ret |= es8374_read_reg(codec, 0x1a, ®); // disable lout reg |= 0x08; ret |= es8374_write_reg(codec, 0x1a, reg); reg &= 0xdf; ret |= es8374_write_reg(codec, 0x1a, reg); ret |= es8374_write_reg(codec, 0x1D, 0x12); // mute speaker ret |= es8374_write_reg(codec, 0x1E, 0x20); // disable class d ret |= es8374_read_reg(codec, 0x15, ®); // power up dac reg &= 0xdf; ret |= es8374_write_reg(codec, 0x15, reg); ret |= es8374_read_reg(codec, 0x1a, ®); // disable lout reg |= 0x20; ret |= es8374_write_reg(codec, 0x1a, reg); reg &= 0xf7; ret |= es8374_write_reg(codec, 0x1a, reg); ret |= es8374_write_reg(codec, 0x1D, 0x02); // mute speaker ret |= es8374_write_reg(codec, 0x1E, 0xa0); // disable class d ret |= es8374_set_voice_mute(codec, false); } return ret; } static int es8374_set_mute(const audio_codec_if_t *h, bool mute) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL || codec->is_open == false) { return ESP_CODEC_DEV_INVALID_ARG; } return es8374_set_voice_mute(codec, mute); } static int es8374_set_vol(const audio_codec_if_t *h, float db_value) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } return es8374_set_adc_dac_volume(codec, ESP_CODEC_DEV_WORK_MODE_DAC, db_value); } static int es8374_set_mic_gain(const audio_codec_if_t *h, float db) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } int ret = _set_mic_gain(codec, db); return ret == 0 ? ESP_CODEC_DEV_OK : ESP_CODEC_DEV_WRITE_FAIL; } static void es8374_pa_power(audio_codec_es8374_t *codec, bool enable) { int16_t pa_pin = codec->cfg.pa_pin; if (pa_pin == -1 || codec->cfg.gpio_if == NULL) { return; } codec->cfg.gpio_if->setup(pa_pin, AUDIO_GPIO_DIR_OUT, AUDIO_GPIO_MODE_FLOAT); codec->cfg.gpio_if->set(pa_pin, codec->cfg.pa_reverted ? !enable : enable); } static int es8374_open(const audio_codec_if_t *h, void *cfg, int cfg_size) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; es8374_codec_cfg_t *codec_cfg = (es8374_codec_cfg_t *) cfg; if (codec == NULL || codec_cfg == NULL || codec_cfg->ctrl_if == NULL || cfg_size != sizeof(es8374_codec_cfg_t)) { return ESP_CODEC_DEV_INVALID_ARG; } int ret = ESP_CODEC_DEV_OK; memcpy(&codec->cfg, codec_cfg, sizeof(es8374_codec_cfg_t)); es_i2s_clock_t clkdiv; clkdiv.lclk_div = LCLK_DIV_256; clkdiv.sclk_div = MCLK_DIV_4; ret |= es8374_stop(codec); ret |= es8374_init_reg(codec, (BIT_LENGTH_16BITS << 4) | ES_I2S_NORMAL, clkdiv, DAC_OUTPUT_ALL, ADC_INPUT_LINPUT1_RINPUT1); ret |= _set_mic_gain(codec, 15); ret |= es8374_set_d2se_pga(codec, D2SE_PGA_GAIN_EN); ret |= es8374_config_fmt(codec, ES_I2S_NORMAL); if (ret != 0) { return ESP_CODEC_DEV_WRITE_FAIL; } codec->is_open = true; return ESP_CODEC_DEV_OK; } static int es8374_close(const audio_codec_if_t *h) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open) { es8374_stop(codec); es8374_write_reg(codec, 0x00, 0x7F); // IC Reset and STOP es8374_pa_power(codec, false); codec->is_open = false; } return ESP_CODEC_DEV_OK; } static int es8374_set_fs(const audio_codec_if_t *h, esp_codec_dev_sample_info_t *fs) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL || codec->is_open == false) { return ESP_CODEC_DEV_INVALID_ARG; } int ret = 0; ret |= es8374_config_fmt(codec, ES_I2S_NORMAL); ret |= es8374_set_bits_per_sample(codec, fs->bits_per_sample); return ESP_CODEC_DEV_OK; } static int es8374_enable(const audio_codec_if_t *h, bool enable) { int ret = ESP_CODEC_DEV_OK; audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } if (codec->enabled == enable) { return ESP_CODEC_DEV_OK; } if (enable) { ret = es8374_start(codec); es8374_pa_power(codec, true); } else { es8374_pa_power(codec, false); ret = es8374_stop(codec); es8374_write_reg(codec, 0x00, 0x7F); // IC Reset and STOP } if (ret == ESP_CODEC_DEV_OK) { codec->enabled = enable; ESP_LOGD(TAG, "Codec is %s", enable ? "enable" : "disable"); } return ret; } static int es8374_set_reg(const audio_codec_if_t *h, int reg, int value) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } return es8374_write_reg(codec, reg, value); } static int es8374_get_reg(const audio_codec_if_t *h, int reg, int *value) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } return es8374_read_reg(codec, reg, value); } static void es8374_dump(const audio_codec_if_t *h) { audio_codec_es8374_t *codec = (audio_codec_es8374_t *) h; if (codec == NULL || codec->is_open == false) { return; } for (int i = 0; i < 50; i++) { int value = 0; int ret = es8374_read_reg(codec, i, &value); if (ret != ESP_CODEC_DEV_OK) { break; } ESP_LOGI(TAG, "%02x: %02x", i, value); } } const audio_codec_if_t *es8374_codec_new(es8374_codec_cfg_t *codec_cfg) { if (codec_cfg == NULL || codec_cfg->ctrl_if == NULL) { ESP_LOGE(TAG, "Wrong codec config"); return NULL; } if (codec_cfg->ctrl_if->is_open(codec_cfg->ctrl_if) == false) { ESP_LOGE(TAG, "Control interface not open yet"); return NULL; } audio_codec_es8374_t *codec = (audio_codec_es8374_t *) calloc(1, sizeof(audio_codec_es8374_t)); if (codec == NULL) { CODEC_MEM_CHECK(codec); return NULL; } codec->base.open = es8374_open; codec->base.enable = es8374_enable; codec->base.set_fs = es8374_set_fs; codec->base.mute = es8374_set_mute; codec->base.set_vol = es8374_set_vol; codec->base.set_mic_gain = es8374_set_mic_gain; codec->base.set_reg = es8374_set_reg; codec->base.get_reg = es8374_get_reg; codec->base.dump_reg = es8374_dump, codec->base.close = es8374_close; do { int ret = codec->base.open(&codec->base, codec_cfg, sizeof(es8374_codec_cfg_t)); if (ret != 0) { ESP_LOGE(TAG, "Open fail"); break; } return &codec->base; } while (0); if (codec) { free(codec); } return NULL; }