766 lines
24 KiB
C

/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#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, &reg);
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, &reg);
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, &reg);
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, &reg); // 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);
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, &reg);
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, &reg);
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, &reg); // 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, &reg);
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);
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, &reg); // 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, &reg); // 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, &reg); // 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, &reg); // 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, &reg); // power up adc and input
reg |= 0xc0;
ret |= es8374_write_reg(codec, 0x10, reg);
ret |= es8374_read_reg(codec, 0x21, &reg); // 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, &reg); // set monomixer
reg |= 0x60;
reg |= 0x20;
reg &= 0xf7;
ret |= es8374_write_reg(codec, 0x1a, reg);
ret |= es8374_read_reg(codec, 0x1c, &reg); // 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, &reg); // power up adc and input
reg &= 0x3f;
ret |= es8374_write_reg(codec, 0x21, reg);
ret |= es8374_read_reg(codec, 0x10, &reg); // 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, &reg); // 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, &reg); // power up dac
reg &= 0xdf;
ret |= es8374_write_reg(codec, 0x15, reg);
ret |= es8374_read_reg(codec, 0x1a, &reg); // 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;
}