/* * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include "es8156_dac.h" #include "es8156_reg.h" #include "esp_log.h" #include "es_common.h" #include "esp_codec_dev_os.h" #define TAG "ES8156" typedef struct { audio_codec_if_t base; const audio_codec_ctrl_if_t *ctrl_if; const audio_codec_gpio_if_t *gpio_if; int16_t pa_pin; bool pa_reverted; bool is_open; bool enabled; float hw_gain; } audio_codec_es8156_t; /* The volume register mapped to decibel table can get from codec data-sheet Volume control register 0x14 description: 0x00 - '-95.5dB' ... 0xFF - '+32dB' */ const esp_codec_dev_vol_range_t vol_range = { .min_vol = { .vol = 0x0, .db_value = -95.5, }, .max_vol = { .vol = 0xFF, .db_value = 32.0, }, }; static int es8156_write_reg(audio_codec_es8156_t *codec, int reg, int value) { return codec->ctrl_if->write_reg(codec->ctrl_if, reg, 1, &value, 1); } static int es8156_read_reg(audio_codec_es8156_t *codec, int reg, int *value) { *value = 0; return codec->ctrl_if->read_reg(codec->ctrl_if, reg, 1, value, 1); } static int es8156_stop(audio_codec_es8156_t *codec) { int ret = 0; ret = es8156_write_reg(codec, 0x14, 0x00); ret |= es8156_write_reg(codec, 0x19, 0x02); ret |= es8156_write_reg(codec, 0x21, 0x1F); ret |= es8156_write_reg(codec, 0x22, 0x02); ret |= es8156_write_reg(codec, 0x25, 0x21); ret |= es8156_write_reg(codec, 0x25, 0xA1); ret |= es8156_write_reg(codec, 0x18, 0x01); ret |= es8156_write_reg(codec, 0x09, 0x02); ret |= es8156_write_reg(codec, 0x09, 0x01); ret |= es8156_write_reg(codec, 0x08, 0x00); return ret; } static int es8156_start(audio_codec_es8156_t *codec) { int ret = 0; ret |= es8156_write_reg(codec, 0x08, 0x3F); ret |= es8156_write_reg(codec, 0x09, 0x00); ret |= es8156_write_reg(codec, 0x18, 0x00); ret |= es8156_write_reg(codec, 0x25, 0x20); ret |= es8156_write_reg(codec, 0x22, 0x00); ret |= es8156_write_reg(codec, 0x21, 0x3C); ret |= es8156_write_reg(codec, 0x19, 0x20); ret |= es8156_write_reg(codec, 0x14, 179); return ret; } static int es8156_set_mute(const audio_codec_if_t *h, bool mute) { audio_codec_es8156_t *codec = (audio_codec_es8156_t *) h; if (codec == NULL || codec->is_open == false) { return ESP_CODEC_DEV_INVALID_ARG; } int regv; int ret = es8156_read_reg(codec, ES8156_DAC_MUTE_REG13, ®v); if (ret < 0) { return ESP_CODEC_DEV_READ_FAIL; } if (mute) { regv = regv | BITS(1) | BITS(2); } else { regv = regv & (~(BITS(1) | BITS(2))); } return es8156_write_reg(codec, ES8156_DAC_MUTE_REG13, (uint8_t) regv); } static int es8156_set_vol(const audio_codec_if_t *h, float volume) { audio_codec_es8156_t *codec = (audio_codec_es8156_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } volume -= codec->hw_gain; int reg = esp_codec_dev_vol_calc_reg(&vol_range, volume); int ret = es8156_write_reg(codec, ES8156_VOLUME_CONTROL_REG14, reg); ESP_LOGD(TAG, "Set volume reg:%x db:%f", reg, volume); return (ret == 0) ? ESP_CODEC_DEV_OK : ESP_CODEC_DEV_WRITE_FAIL; } static void es8156_pa_power(audio_codec_es8156_t *codec, es_pa_setting_t pa_setting) { int16_t pa_pin = codec->pa_pin; if (pa_pin == -1 || codec->gpio_if == NULL) { return; } if (pa_setting & ES_PA_SETUP) { codec->gpio_if->setup(pa_pin, AUDIO_GPIO_DIR_OUT, AUDIO_GPIO_MODE_FLOAT); } if (pa_setting & ES_PA_ENABLE) { codec->gpio_if->set(pa_pin, codec->pa_reverted ? false : true); } if (pa_setting & ES_PA_DISABLE) { codec->gpio_if->set(pa_pin, codec->pa_reverted ? true : false); } } static int es8156_open(const audio_codec_if_t *h, void *cfg, int cfg_size) { audio_codec_es8156_t *codec = (audio_codec_es8156_t *) h; es8156_codec_cfg_t *codec_cfg = (es8156_codec_cfg_t *) cfg; if (codec == NULL || codec_cfg == NULL || cfg_size != sizeof(es8156_codec_cfg_t) || codec_cfg->ctrl_if == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } int ret = ESP_CODEC_DEV_OK; codec->ctrl_if = codec_cfg->ctrl_if; codec->gpio_if = codec_cfg->gpio_if; codec->pa_pin = codec_cfg->pa_pin; codec->pa_reverted = codec_cfg->pa_reverted; ret |= es8156_write_reg(codec, 0x02, 0x04); ret |= es8156_write_reg(codec, 0x20, 0x2A); ret |= es8156_write_reg(codec, 0x21, 0x3C); ret |= es8156_write_reg(codec, 0x22, 0x00); ret |= es8156_write_reg(codec, 0x24, 0x07); ret |= es8156_write_reg(codec, 0x23, 0x00); ret |= es8156_write_reg(codec, 0x0A, 0x01); ret |= es8156_write_reg(codec, 0x0B, 0x01); ret |= es8156_write_reg(codec, 0x11, 0x00); ret |= es8156_write_reg(codec, 0x14, 179); // volume 70% ret |= es8156_write_reg(codec, 0x0D, 0x14); ret |= es8156_write_reg(codec, 0x18, 0x00); ret |= es8156_write_reg(codec, 0x08, 0x3F); ret |= es8156_write_reg(codec, 0x00, 0x02); ret |= es8156_write_reg(codec, 0x00, 0x03); ret |= es8156_write_reg(codec, 0x25, 0x20); if (ret != 0) { return ESP_CODEC_DEV_WRITE_FAIL; } es8156_pa_power(codec, ES_PA_SETUP | ES_PA_ENABLE); codec->is_open = true; return ESP_CODEC_DEV_OK; } static int es8156_close(const audio_codec_if_t *h) { audio_codec_es8156_t *codec = (audio_codec_es8156_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open) { es8156_stop(codec); es8156_pa_power(codec, ES_PA_DISABLE); codec->is_open = false; } return ESP_CODEC_DEV_OK; } static int es8156_enable(const audio_codec_if_t *h, bool enable) { int ret = ESP_CODEC_DEV_OK; audio_codec_es8156_t *codec = (audio_codec_es8156_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 = es8156_start(codec); es8156_pa_power(codec, ES_PA_ENABLE); } else { es8156_pa_power(codec, ES_PA_DISABLE); ret = es8156_stop(codec); } if (ret == ESP_CODEC_DEV_OK) { codec->enabled = enable; ESP_LOGD(TAG, "Codec is %s", enable ? "enabled" : "disabled"); } return ret; } static int es8156_set_reg(const audio_codec_if_t *h, int reg, int value) { audio_codec_es8156_t *codec = (audio_codec_es8156_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } return es8156_write_reg(codec, reg, value); } static int es8156_get_reg(const audio_codec_if_t *h, int reg, int *value) { audio_codec_es8156_t *codec = (audio_codec_es8156_t *) h; if (codec == NULL) { return ESP_CODEC_DEV_INVALID_ARG; } if (codec->is_open == false) { return ESP_CODEC_DEV_WRONG_STATE; } return es8156_read_reg(codec, reg, value); } static void es8156_dump(const audio_codec_if_t *h) { audio_codec_es8156_t *codec = (audio_codec_es8156_t *) h; if (codec == NULL || codec->is_open == false) { return; } for (int i = 0; i <= 0x25; i++) { int value = 0; int ret = es8156_read_reg(codec, i, &value); if (ret != ESP_CODEC_DEV_OK) { break; } ESP_LOGI(TAG, "%02x: %02x", i, value); } } const audio_codec_if_t *es8156_codec_new(es8156_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_es8156_t *codec = (audio_codec_es8156_t *) calloc(1, sizeof(audio_codec_es8156_t)); if (codec == NULL) { CODEC_MEM_CHECK(codec); return NULL; } codec->ctrl_if = codec_cfg->ctrl_if; codec->base.open = es8156_open; codec->base.enable = es8156_enable; codec->base.set_vol = es8156_set_vol; codec->base.mute = es8156_set_mute; codec->base.set_reg = es8156_set_reg; codec->base.get_reg = es8156_get_reg; codec->base.dump_reg = es8156_dump; codec->base.close = es8156_close; codec->hw_gain = esp_codec_dev_col_calc_hw_gain(&codec_cfg->hw_gain); do { int ret = codec->base.open(&codec->base, codec_cfg, sizeof(es8156_codec_cfg_t)); if (ret != 0) { ESP_LOGE(TAG, "Open fail"); break; } return &codec->base; } while (0); if (codec) { free(codec); } return NULL; }