/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <string.h>
#include "es8389_reg.h"
#include "es8389_codec.h"
#include "es_common.h"
#include "esp_log.h"

#define TAG          "ES8389"

typedef struct {
    audio_codec_if_t   base;
    es8389_codec_cfg_t cfg;
    bool               is_open;
    bool               enabled;
    float              hw_gain;
    bool               use_mclk;
} audio_codec_es8389_t;

/*
* Clock coefficient structure
*/
struct _coeff_div {
    uint16_t Ratio;
    uint32_t MCLK;
    uint32_t LRCK;
    uint8_t  Reg0x04;
    uint8_t  Reg0x05;
    uint8_t  Reg0x06;
    uint8_t  Reg0x07;
    uint8_t  Reg0x08;
    uint8_t  Reg0x09;
    uint8_t  Reg0x0A;
    uint8_t  Reg0x0F;
    uint8_t  Reg0x11;
    uint8_t  Reg0x21;
    uint8_t  Reg0x22;
    uint8_t  Reg0x26;
    uint8_t  Reg0x30;
    uint8_t  Reg0x41;
    uint8_t  Reg0x42;
    uint8_t  Reg0x43;
    uint8_t  Reg0xF0;
    uint8_t  Reg0xF1;
    uint8_t  Reg0x16;
    uint8_t  Reg0x18;
    uint8_t  Reg0x19;
};

/* codec hifi mclk clock divider coefficients */

static const struct _coeff_div coeff_div[] = {
    //	Ratio	Freq MCLK	FreqLRCK,Reg0x04,Reg0x05,Reg0x06,Reg0x07,Reg0x08,Reg0x09,Reg0x0A,Reg0x0F,Reg0x11,Reg0x21,Reg0x22,Reg0x26,Reg0x30,Reg0x41,Reg0x42,Reg0x43,Reg0xF0,Reg0xF1,Reg0x16,Reg0x18,Reg0x19
    {32		,256000		,8000	,0x00	,0x57	,0x84	,0xD0	,0x03	,0xC1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12	,0x00	,0x09	,0x19	,0x07},
    {36		,288000		,8000	,0x00	,0x55	,0x84	,0xD0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x23	,0x8F	,0xB7	,0xC0	,0x1F	,0x8F	,0x01	,0x12	,0x00	,0x09	,0x19	,0x07},
    {48		,384000		,8000	,0x02	,0x5F	,0x04	,0xC0	,0x03	,0xC1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {64		,512000		,8000	,0x00	,0x4D	,0x24	,0xC0	,0x03	,0xD1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {72		,576000		,8000	,0x00	,0x45	,0x24	,0xC0	,0x01	,0xD1	,0x90	,0x00	,0x00	,0x23	,0x8F	,0xB7	,0xC0	,0x1F	,0x8F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {96		,768000		,8000	,0x02	,0x57	,0x84	,0xD0	,0x03	,0xC1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {128	,1024000	,8000	,0x00	,0x45	,0x04	,0xD0	,0x03	,0xC1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {192	,1536000	,8000	,0x02	,0x4D	,0x24	,0xC0	,0x03	,0xD1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {256	,2048000	,8000	,0x01	,0x45	,0x04	,0xD0	,0x03	,0xC1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {288	,2304000	,8000	,0x01	,0x51	,0x00	,0xC0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x23	,0x8F	,0xB7	,0xC0	,0x1F	,0x8F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {384	,3072000	,8000	,0x02	,0x45	,0x04	,0xD0	,0x03	,0xC1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {512	,4096000	,8000	,0x00	,0x41	,0x04	,0xE0	,0x00	,0xD1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {768	,6144000	,8000	,0x05	,0x45	,0x04	,0xD0	,0x03	,0xC1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {1024	,8192000	,8000	,0x01	,0x41	,0x06	,0xE0	,0x00	,0xD1	,0xB0	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {1536	,12288000	,8000	,0x02	,0x41	,0x04	,0xE0	,0x00	,0xD1	,0xB0	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {1625	,13000000	,8000	,0x40	,0x6E	,0x05	,0xC8	,0x01	,0xC2	,0x90	,0x40	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {2048	,16384000	,8000	,0x03	,0x44	,0x01	,0xC0	,0x00	,0xD2	,0x80	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {2304	,18432000	,8000	,0x11	,0x45	,0x25	,0xF0	,0x00	,0xD1	,0xB0	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {3072	,24576000	,8000	,0x05	,0x44	,0x01	,0xC0	,0x00	,0xD2	,0x80	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x01	,0x12   ,0x00	,0x09	,0x19	,0x07},
    {32		,512000		,16000	,0x00	,0x55	,0x84	,0xD0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {36		,576000		,16000	,0x00	,0x55	,0x84	,0xD0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x23	,0x8F	,0xB7	,0xC0	,0x1F	,0x8F	,0x01	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {48		,768000		,16000	,0x02	,0x57	,0x04	,0xC0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {50		,800000		,16000	,0x00	,0x7E	,0x01	,0xD9	,0x00	,0xC2	,0x80	,0x00	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0xC7	,0x95	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {64		,1024000	,16000	,0x00	,0x45	,0x24	,0xC0	,0x01	,0xD1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {72		,1152000	,16000	,0x00	,0x45	,0x24	,0xC0	,0x01	,0xD1	,0x90	,0x00	,0x00	,0x23	,0x8F	,0xB7	,0xC0	,0x1F	,0x8F	,0x01	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {96		,1536000	,16000	,0x02	,0x55	,0x84	,0xD0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {128	,2048000	,16000	,0x00	,0x51	,0x04	,0xD0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {144	,2304000	,16000	,0x00	,0x51	,0x00	,0xC0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x23	,0x8F	,0xB7	,0xC0	,0x1F	,0x8F	,0x01	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {192	,3072000	,16000	,0x02	,0x65	,0x25	,0xE0	,0x00	,0xE1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {256	,4096000	,16000	,0x00	,0x41	,0x04	,0xC0	,0x01	,0xD1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {300	,4800000	,16000	,0x02	,0x66	,0x01	,0xD9	,0x00	,0xC2	,0x80	,0x00	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0xC7	,0x95	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {384	,6144000	,16000	,0x02	,0x51	,0x04	,0xD0	,0x01	,0xC1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {512	,8192000	,16000	,0x01	,0x41	,0x04	,0xC0	,0x01	,0xD1	,0x90	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {750	,12000000	,16000	,0x0E	,0x7E	,0x01	,0xC9	,0x00	,0xC2	,0x80	,0x40	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0xC7	,0x95	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {768	,12288000	,16000	,0x02	,0x41	,0x04	,0xC0	,0x01	,0xD1	,0x90	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {1024	,16384000	,16000	,0x03	,0x41	,0x04	,0xC0	,0x01	,0xD1	,0x90	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {1152	,18432000	,16000	,0x08	,0x51	,0x04	,0xD0	,0x01	,0xC1	,0x90	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {1200	,19200000	,16000	,0x0B	,0x66	,0x01	,0xD9	,0x00	,0xC2	,0x80	,0x40	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0xC7	,0x95	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {1500	,24000000	,16000	,0x0E	,0x26	,0x01	,0xD9	,0x00	,0xC2	,0x80	,0xC0	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0xC7	,0x95	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {1536	,24576000	,16000	,0x05	,0x41	,0x04	,0xC0	,0x01	,0xD1	,0x90	,0xC0	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0xFF	,0x7F	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {1625	,26000000	,16000	,0x40	,0x6E	,0x05	,0xC8	,0x01	,0xC2	,0x90	,0xC0	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x12	,0x31	,0x0E},
    {800	,19200000	,24000	,0x07	,0x66	,0x01	,0xD9	,0x00	,0xC2	,0x80	,0x40	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0xC7	,0x95	,0x00	,0x12   ,0x00	,0x1A	,0x49	,0x14},
    {600	,19200000	,32000	,0x05	,0x46	,0x01	,0xD8	,0x10	,0xD2	,0x80	,0x40	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x23	,0x61	,0x1B},
    {32		,1411200	,44100	,0x00	,0x45	,0xA4	,0xD0	,0x10	,0xD1	,0x80	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {64		,2822400	,44100	,0x00	,0x51	,0x00	,0xC0	,0x10	,0xC1	,0x80	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {128	,5644800	,44100	,0x00	,0x41	,0x04	,0xD0	,0x10	,0xD1	,0x80	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {256	,11289600	,44100	,0x01	,0x41	,0x04	,0xD0	,0x10	,0xD1	,0x80	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {512	,22579200	,44100	,0x03	,0x41	,0x04	,0xD0	,0x10	,0xD1	,0x80	,0xC0	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {32		,1536000	,48000	,0x00	,0x45	,0xA4	,0xD0	,0x10	,0xD1	,0x80	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {48		,2304000	,48000	,0x02	,0x55	,0x04	,0xC0	,0x10	,0xC1	,0x80	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {50		,2400000	,48000	,0x00	,0x76	,0x01	,0xC8	,0x10	,0xC2	,0x80	,0x00	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {64		,3072000	,48000	,0x00	,0x51	,0x04	,0xC0	,0x10	,0xC1	,0x80	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {100	,4800000	,48000	,0x00	,0x46	,0x01	,0xD8	,0x10	,0xD2	,0x80	,0x00	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {125	,6000000	,48000	,0x04	,0x6E	,0x05	,0xC8	,0x10	,0xC2	,0x80	,0x00	,0x01	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {128	,6144000	,48000	,0x00	,0x41	,0x04	,0xD0	,0x10	,0xD1	,0x80	,0x00	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {200	,9600000	,48000	,0x01	,0x46	,0x01	,0xD8	,0x10	,0xD2	,0x80	,0x00	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {250	,12000000	,48000	,0x04	,0x76	,0x01	,0xC8	,0x10	,0xC2	,0x80	,0x40	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {256	,12288000	,48000	,0x01	,0x41	,0x04	,0xD0	,0x10	,0xD1	,0x80	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {384	,18432000	,48000	,0x02	,0x41	,0x04	,0xD0	,0x10	,0xD1	,0x80	,0x40	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {400	,19200000	,48000	,0x03	,0x46	,0x01	,0xD8	,0x10	,0xD2	,0x80	,0x40	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {500	,24000000	,48000	,0x04	,0x46	,0x01	,0xD8	,0x10	,0xD2	,0x80	,0xC0	,0x00	,0x18	,0x95	,0xD0	,0xC0	,0x63	,0x95	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {512	,24576000	,48000	,0x03	,0x41	,0x04	,0xD0	,0x10	,0xD1	,0x80	,0xC0	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {800	,38400000	,48000	,0x18	,0x45	,0x04	,0xC0	,0x10	,0xC1	,0x80	,0xC0	,0x00	,0x1F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x00	,0x12   ,0x00	,0x35	,0x91	,0x28},
    {128	,11289600	,88200	,0x00	,0x50	,0x00	,0xC0	,0x10	,0xC1	,0x80	,0x40	,0x00	,0x9F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x80	,0x12   ,0xC0	,0x32	,0x89	,0x25},
    {64		,6144000	,96000	,0x00	,0x41	,0x00	,0xD0	,0x10	,0xD1	,0x80	,0x00	,0x00	,0x9F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x80	,0x12   ,0xC0	,0x35	,0x91	,0x28},
    {256	,24576000	,96000	,0x00	,0x40	,0x00	,0xC0	,0x10	,0xC1	,0x80	,0xC0	,0x00	,0x9F	,0x7F	,0xBF	,0xC0	,0x7F	,0x7F	,0x80	,0x12   ,0xC0	,0x35	,0x91	,0x28},
    {128	,24576000	,192000	,0x00	,0x50	,0x00	,0xC0	,0x18	,0xC1	,0x81	,0xC0	,0x00	,0x8F	,0x7F	,0xEF	,0xC0	,0x3F	,0x7F	,0x80	,0x12   ,0xC0	,0x3F	,0xF9	,0x3F},
    {50		,400000		,8000	,0x00	,0x75	,0x05	,0xC8	,0x01	,0xC1	,0x90	,0x10	,0x00	,0x18	,0xC7	,0xD0	,0xC0	,0x8F	,0xC7	,0x01	,0x12	,0x00	,0x09	,0x19	,0x07},
    {600	,4800000	,8000	,0x05	,0x65	,0x25	,0xF9	,0x00	,0xD1	,0x90	,0x10	,0x00	,0x18	,0xC7	,0xD0	,0xC0	,0x8F	,0xC7	,0x01	,0x12	,0x00	,0x09	,0x19	,0x07},
    {1500	,12000000	,8000	,0x0E	,0x25	,0x25	,0xE8	,0x00	,0xD1	,0x90	,0x40	,0x00	,0x31	,0xC7	,0xC5	,0x00	,0x8F	,0xC7	,0x01	,0x12	,0x00	,0x09	,0x19	,0x07},
    {2400	,19200000	,8000	,0x0B	,0x01	,0x00	,0xD0	,0x00	,0xD1	,0x80	,0x90	,0x00	,0x31	,0xC7	,0xC5	,0x00	,0xC7	,0xC7	,0x00	,0x12	,0x00	,0x09	,0x19	,0x07},
    {3000	,24000000	,8000	,0x0E	,0x24	,0x05	,0xD0	,0x00	,0xC2	,0x80	,0xC0	,0x00	,0x31	,0xC7	,0xC5	,0x00	,0x8F	,0xC7	,0x01	,0x12	,0x00	,0x09	,0x19	,0x07},
    {3250	,26000000	,8000	,0x40	,0x05	,0xA4	,0xC0	,0x00	,0xD1	,0x80	,0xD0	,0x00	,0x31	,0xC7	,0xC5	,0x00	,0xC7	,0xC7	,0x00	,0x12	,0x00	,0x09	,0x19	,0x07},
};

static 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 es8389_write_reg(audio_codec_es8389_t *codec, int reg, int value)
{
    return codec->cfg.ctrl_if->write_reg(codec->cfg.ctrl_if, reg, 1, &value, 1);
}

static int es8389_read_reg(audio_codec_es8389_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 es8389_update_bits(audio_codec_es8389_t *codec, uint8_t reg_addr, uint8_t mask, uint8_t val)
{
    int regval = 0;

    es8389_read_reg(codec, reg_addr, &regval);
    regval &= ~mask;
    regval |= (val & mask);
    return es8389_write_reg(codec, reg_addr, regval);
}

int es8389_set_bias_standby(audio_codec_es8389_t *codec)
{
    int ret = es8389_update_bits(codec, ES8389_DAC_CONTROL_REG0x40, 0x03, 0x03);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x10, 0xD4);
    vTaskDelay(pdMS_TO_TICKS(70));
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x61, 0x59);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x64, 0x00);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x03, 0x00);
    ret |= es8389_write_reg(codec, ES8389_RESET_REG0x00, 0x7E);
    ret |= es8389_update_bits(codec, ES8389_DAC_CONTROL_REG0x40, 0x03, 0x00);

    return ret;
}

int es8389_set_bias_on(audio_codec_es8389_t *codec)
{
    int ret = es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x4D, 0x02);
    ret |= es8389_update_bits(codec, ES8389_ANALOG_CONTROL_REG0x69, 0x20, 0x20);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x61, 0xD9);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x64, 0x8F);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x10, 0xE4);
    ret |= es8389_write_reg(codec, ES8389_RESET_REG0x00, 0x01);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x03, 0xC3);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x24, 0x6A);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x25, (uint8_t)(0x0A + (0 << 6) + (0 << 5)));

    return ret;
}

static int es8389_config_fmt(audio_codec_es8389_t *codec, es_i2s_fmt_t fmt)
{
    int ret = ESP_CODEC_DEV_OK;
    int state = 0 ;

    switch (fmt) {
        case ES_I2S_NORMAL:
            ESP_LOGD(TAG, "es8389 in I2S Format");
            state |= ES8389_DAIFMT_I2S;
            ret |= es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x0C, 0xE0, 0x00);
            break;
        case ES_I2S_LEFT:
        case ES_I2S_RIGHT:
            ESP_LOGD(TAG, "es8389 in LJ Format");
            state |= ES8389_DAIFMT_LEFT_J;
            ret |= es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x0C, 0xE0, 0x40);
            break;
        case ES_I2S_DSP:
            ESP_LOGD(TAG, "es8389 in DSP-A Format");
            state |= ES8389_DAIFMT_DSP_A;
            ret |= es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x0C, 0xE0, 0x80);
            break;
        default:
            ESP_LOGD(TAG, "es8389 in DSP-B Format");
            state |= ES8389_DAIFMT_DSP_B;
            ret |= es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x0C, 0xE0, 0xA0);
            break;
    }

    ret |= es8389_update_bits(codec, ES8389_ADC_SP_CONTROL_REG0x20, ES8389_MASK_DAIFMT, state);
    ret |= es8389_update_bits(codec, ES8389_DAC_CONTROL_REG0x40, ES8389_MASK_DAIFMT, state);

    return ret;
}

static int es8389_set_bits_per_sample(audio_codec_es8389_t *codec, int bits)
{
    int ret = ESP_CODEC_DEV_OK;
    int state = 0 ;

    switch (bits) {
        case 16:
        default:
            state |= ES8389_S16_LE;
            break;
        case 18:
            state |= ES8389_S18_LE;
            break;
        case 20:
            state |= ES8389_S20_LE;
            break;
        case 24:
            state |= ES8389_S24_LE;
            break;
        case 32:
            state |= ES8389_S32_LE;
            break;
    }

    ret |= es8389_update_bits(codec, ES8389_ADC_SP_CONTROL_REG0x20, ES8389_MASK_DATALEN, state);
    ret |= es8389_update_bits(codec, ES8389_DAC_CONTROL_REG0x40, ES8389_MASK_DATALEN, state);

    return ret;
}

static int get_coeff(uint32_t mclk, uint32_t rate)
{
    for (int i = 0; i < (sizeof(coeff_div) / sizeof(coeff_div[0])); i++) {
        if(coeff_div[i].Ratio == rate && coeff_div[i].MCLK == mclk) {
            return i;
        }
    }

    return ESP_CODEC_DEV_NOT_FOUND;
}

static int es8389_suspend(audio_codec_es8389_t *codec)
{
    int ret = ESP_CODEC_DEV_OK;
    ret |= es8389_update_bits(codec, ES8389_DAC_CONTROL_REG0x40, 0x03, 0x03);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x10, 0xD4);
    vTaskDelay(pdMS_TO_TICKS(70));
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x61, 0x59);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x64, 0x00);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x63, 0x00);
    ret |= es8389_write_reg(codec, ES8389_RESET_REG0x00, 0x7E);
    ret |= es8389_update_bits(codec, ES8389_DAC_CONTROL_REG0x40, 0x03, 0x00);

    ret |= es8389_write_reg(codec, ES8389_MISC_CONTROL_REG0x01, 0x28);
    ret |= es8389_update_bits(codec, ES8389_ANALOG_CONTROL_REG0x69, 0x20, 0x00);
    ret |= es8389_write_reg(codec, ES8389_VMID_CONTROL_REG0x60, 0x00);
    ret |= es8389_write_reg(codec, ES8389_RESET_REG0x00, 0x00);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x10, 0xCC);
    vTaskDelay(pdMS_TO_TICKS(500));
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x10, 0x00);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x61, 0x08);
    ret |= es8389_write_reg(codec, ES8389_ISOLATION_CONTROL_REG0xF3, 0xC1);
    ret |= es8389_write_reg(codec, ES8389_PULL_DOWN_CONTROL_REG0xF2, 0x00);

    return ret;
}

static int es8389_start(audio_codec_es8389_t *codec)
{
    int ret = ESP_CODEC_DEV_OK;
    ret |= es8389_set_bias_on(codec);

    return ret;
}

static int es8389_set_mute(const audio_codec_if_t *h, bool mute)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;

    if (codec == NULL || codec->is_open == false) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    int regv;

    int ret = es8389_read_reg(codec, ES8389_ADC_SP_CONTROL_REG0x20, &regv);
    regv &= 0xFC;
    if (mute) {
        regv |= 0x03;
    }
    es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x20, regv);
    return ret;
}

static int es8389_set_vol(const audio_codec_if_t *h, float db_value)
{
    int ret = ESP_CODEC_DEV_OK;
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;

    if (codec == NULL) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    if (codec->is_open == false) {
        return ESP_CODEC_DEV_WRONG_STATE;
    }

    db_value -= codec->hw_gain;
    int reg = esp_codec_dev_vol_calc_reg(&vol_range, db_value);
    ESP_LOGD(TAG, "Set volume reg:%x db:%d", reg, (int) db_value);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x46, (uint8_t) reg);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x47, (uint8_t) reg);
    return ret;
}

static int es8389_set_mic_gain(const audio_codec_if_t *h, float db)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *)h;
    if (codec == NULL) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    if (codec->is_open == false) {
        return ESP_CODEC_DEV_WRONG_STATE;
    }
    es8389_mic_gain_t gain_db = ES8389_MIC_GAIN_0DB;
    if (db < 6) {
        gain_db = ES8389_MIC_GAIN_3_5DB;
    } else if (db < 9) {
        gain_db = ES8389_MIC_GAIN_6_5DB;
    } else if (db < 12) {
        gain_db = ES8389_MIC_GAIN_9_5DB;
    } else if (db < 15) {
        gain_db = ES8389_MIC_GAIN_12_5DB;
    } else if (db < 18) {
        gain_db = ES8389_MIC_GAIN_15_5DB;
    } else if (db < 21) {
        gain_db = ES8389_MIC_GAIN_18_5DB;
    } else if (db < 24) {
        gain_db = ES8389_MIC_GAIN_21_5DB;
    } else if (db < 27) {
        gain_db = ES8389_MIC_GAIN_24_5DB;
    } else if (db < 30) {
        gain_db = ES8389_MIC_GAIN_27_5DB;
    } else if (db < 33) {
        gain_db = ES8389_MIC_GAIN_30_5DB;
    } else if (db < 36) {
        gain_db = ES8389_MIC_GAIN_33_5DB;
    } else {
        gain_db = ES8389_MIC_GAIN_36_5DB;
    }
    int ret = es8389_write_reg(codec, ES8389_PGA1_GAIN_CONTROL_REG0x72, gain_db | (3 << 4));  // MIC gain scale
    return ret == 0 ? ESP_CODEC_DEV_OK : ESP_CODEC_DEV_WRITE_FAIL;
}

static void es8389_pa_power(audio_codec_es8389_t *codec, es_pa_setting_t pa_setting)
{
    int16_t pa_pin = codec->cfg.pa_pin;
    if (pa_pin == -1 || codec->cfg.gpio_if == NULL) {
        return;
    }
    if (pa_setting & ES_PA_SETUP) {
        codec->cfg.gpio_if->setup(pa_pin, AUDIO_GPIO_DIR_OUT, AUDIO_GPIO_MODE_FLOAT);
    }
    if (pa_setting & ES_PA_ENABLE) {
        codec->cfg.gpio_if->set(pa_pin, codec->cfg.pa_reverted ? false : true);
    }
    if (pa_setting & ES_PA_DISABLE) {
        codec->cfg.gpio_if->set(pa_pin, codec->cfg.pa_reverted ? true : false);
    }
}

static int es8389_config_sample(audio_codec_es8389_t *codec, int sample_rate, int bits)
{
    int ret = ESP_CODEC_DEV_OK;
    int mclk_fre = sample_rate * bits * 2;
    int rate = mclk_fre / sample_rate;

    int coeff = get_coeff(mclk_fre, rate);

    if (coeff < 0) {
        ESP_LOGE(TAG, "Unable to configure sample rate %dHz with %dHz MCLK", sample_rate, mclk_fre);
        return ESP_CODEC_DEV_NOT_SUPPORT;
    } else {
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x04, coeff_div[coeff].Reg0x04);
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x05, coeff_div[coeff].Reg0x05);
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x06, coeff_div[coeff].Reg0x06);
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x07, coeff_div[coeff].Reg0x07);
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x08, coeff_div[coeff].Reg0x08);
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x09, coeff_div[coeff].Reg0x09);
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x0A, coeff_div[coeff].Reg0x0A);
        ret |= es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x0F, 0xC0, coeff_div[coeff].Reg0x0F);
        ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x11, coeff_div[coeff].Reg0x11);
        ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x21, coeff_div[coeff].Reg0x21);
        ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x22, coeff_div[coeff].Reg0x22);
        ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x26, coeff_div[coeff].Reg0x26);
        ret |= es8389_update_bits(codec, 0x30, 0xC0, coeff_div[coeff].Reg0x30);
        ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x41, coeff_div[coeff].Reg0x41);
        ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x42, coeff_div[coeff].Reg0x42);
        ret |= es8389_update_bits(codec, ES8389_DAC_CONTROL_REG0x43, 0x81, coeff_div[coeff].Reg0x43);
        ret |= es8389_update_bits(codec, ES8389_CHIP_MISC_CONTROL_REG0xF0, 0x73, coeff_div[coeff].Reg0xF0);
        ret |= es8389_write_reg(codec, ES8389_CSM_STATE_REG0xF1, coeff_div[coeff].Reg0xF1);
        ret |= es8389_write_reg(codec, 0x16, coeff_div[coeff].Reg0x16);
        ret |= es8389_write_reg(codec, 0x18, coeff_div[coeff].Reg0x18);
        ret |= es8389_write_reg(codec, 0x19, coeff_div[coeff].Reg0x19);
    }

    return ret == 0 ? ESP_CODEC_DEV_OK : ESP_CODEC_DEV_WRITE_FAIL;
}

static int es8389_open(const audio_codec_if_t *h, void *cfg, int cfg_size)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *)h;
    es8389_codec_cfg_t *codec_cfg = (es8389_codec_cfg_t *)cfg;
    if (codec == NULL || codec_cfg == NULL || codec_cfg->ctrl_if == NULL || cfg_size != sizeof(es8389_codec_cfg_t)) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    memcpy(&codec->cfg, cfg, sizeof(es8389_codec_cfg_t));
    if (codec->cfg.mclk_div == 0) {
        codec->cfg.mclk_div = MCLK_DEFAULT_DIV;
    }

    int ret = ESP_CODEC_DEV_OK;

    ret |= es8389_write_reg(codec, ES8389_ISOLATION_CONTROL_REG0xF3, 0x00);
    ret |= es8389_write_reg(codec, ES8389_RESET_REG0x00, 0x7E);
    ret |= es8389_write_reg(codec, ES8389_ISOLATION_CONTROL_REG0xF3, 0x38);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x24, 0x64);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x25, (int)(0x04 + (0 << 6) + (0 << 5)));
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x45, (int)(0x03 + (0 << 6) + (0 << 5)));
    ret |= es8389_write_reg(codec, ES8389_VMID_CONTROL_REG0x60, 0x2A);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x61, 0xC9);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x62, 0x4F);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x63, 0x06);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x6B, 0x00);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x6D, (int)(0x16 + (0 & 0xC0)));
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x6E, 0xAA);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x6F, 0x66);
    ret |= es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x70, 0x99);

    if (ES8389_Analog_DriveSel == ES8389_DriveSel_LowPower) {
        es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x6B, 0x80);
        es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x6C, 0x0F);
        es8389_write_reg(codec, ES8389_ANALOG_CONTROL_REG0x70, 0x66);
    }

    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x23, (int)(0x00 + (0 & 0xC0) + (0 << 2) + (0 & 0x03)));
    ret |= es8389_write_reg(codec, ES8389_PGA1_GAIN_CONTROL_REG0x72, (int)((1 << 4) + 0));
    ret |= es8389_write_reg(codec, ES8389_PGA1_GAIN_CONTROL_REG0x73, (int)((1 << 4) + 0));
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x10, 0xC4);
    ret |= es8389_write_reg(codec, ES8389_MISC_CONTROL_REG0x01, (int)(0x08 + (0 << 7) + (0 << 6) + (0 << 5) + (0 << 0)));
    ret |= es8389_write_reg(codec, ES8389_CSM_STATE_REG0xF1, 0x00);
    ret |= es8389_write_reg(codec, 0x12, 0x01);
    ret |= es8389_write_reg(codec, 0x13, 0x01);
    ret |= es8389_write_reg(codec, 0x14, 0x01);
    ret |= es8389_write_reg(codec, 0x15, 0x01);
    ret |= es8389_write_reg(codec, 0x16, 0x35);
    ret |= es8389_write_reg(codec, 0x17, 0x09);
    ret |= es8389_write_reg(codec, 0x18, 0x91);
    ret |= es8389_write_reg(codec, 0x19, 0x28);
    ret |= es8389_write_reg(codec, 0x1A, 0x01);
    ret |= es8389_write_reg(codec, 0x1B, 0x01);
    ret |= es8389_write_reg(codec, 0x1C, 0x11);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x2A, (int)(0x00 + (0 << 4)));
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x20, (int)(0x00 + ES8389_S16_LE + (0 << 4) + ES8389_DAIFMT_I2S + (0 << 1) + (0 << 0)));
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x40, (int)(0x00 + ES8389_S16_LE + (0 << 4) + ES8389_DAIFMT_I2S + (0 << 1) + (0 << 0)));
    ret |= es8389_write_reg(codec, ES8389_CHIP_MISC_CONTROL_REG0xF0, (int)(0x1 + (0 << 3) + (0 << 2)));
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x02, (int)(0x00 + (0 << 6) + (0 << 1) + (0 << 0)));
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x04, 0x00);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x05, 0x10);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x06, 0x00);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x07, 0xC0);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x08, 0x00);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x09, 0xC0);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x0A, 0x80);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x0B, 4);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x0C, (int)(256 >> 8));
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x0D, (int)(256 & 0xFF));
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x0F, 0x10);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x21, 0x1F);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x22, 0x7F);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x2F, 0xC0);
    ret |= es8389_write_reg(codec, 0x30, 0xF4);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x31, (int)(0x00 + (0 << 7) + (0 << 6)));
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x44, (int)(0x00 + (0 << 3) + (0 << 2) + (0 << 1) + (0 << 0)));
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x41, 0x7F);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x42, 0x7F);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x43, 0x10);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x49, (int)(0x0F + (0 << 4)));
    ret |= es8389_write_reg(codec, 0x4C, 0xC0);

    ret |= es8389_write_reg(codec, ES8389_RESET_REG0x00, 0x00);
    ret |= es8389_write_reg(codec, ES8389_CLK_MANAGER_REG0x03, 0xC1);
    ret |= es8389_write_reg(codec, ES8389_RESET_REG0x00, 0x01);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x4D, 0x02);

    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x26, 191);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x27, 191);
    ret |= es8389_write_reg(codec, ES8389_ADC_SP_CONTROL_REG0x28, 191);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x46, 191);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x47, 191);
    ret |= es8389_write_reg(codec, ES8389_DAC_CONTROL_REG0x48, (int)(95 << 1));

    if (codec_cfg->master_mode) {
        ESP_LOGI(TAG, "Work in Master mode");
        es8389_update_bits(codec, ES8389_MISC_CONTROL_REG0x01, ES8389_MASK_MSModeSel, 1);
    } else {
        ESP_LOGI(TAG, "Work in Slave mode");
        es8389_update_bits(codec, ES8389_MISC_CONTROL_REG0x01, ES8389_MASK_MSModeSel, 0);
    }

    // Select clock source for internal mclk
    if (codec_cfg->use_mclk) {
        es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x02, 0xC0, 0 << 6);
        codec->use_mclk = true;
    } else {
        es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x02, 0xC0, 1 << 6);
        codec->use_mclk = false;
    }
    // MCLK inverted or not
    if (codec_cfg->invert_mclk) {
        es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x02, 0x02, 1 << 1);
    } else {
        es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x02, 0x02, 0 << 1);
    }

    // Set ADC and DAC data format
    if (codec_cfg->no_dac_ref == false) {
        /* set internal reference signal (ADCL + DACR) */
        ret |= es8389_write_reg(codec, ES8389_CHIP_MISC_CONTROL_REG0xF0, (int)(0x12 + (1 << 3) + (0 << 2)));
        ESP_LOGI(TAG, "Set internal reference signal");
    } else {
        ret |= es8389_write_reg(codec, ES8389_CHIP_MISC_CONTROL_REG0xF0, (int)(0x12 + (0 << 3) + (0 << 2)));
    }

    // SCLK inverted or not
    if (codec_cfg->invert_sclk) {
        es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x02, 0x01, 1 << 0);
    } else {
        es8389_update_bits(codec, ES8389_CLK_MANAGER_REG0x02, 0x01, 0 << 0);
    }

    if (ret != 0) {
        return ESP_CODEC_DEV_WRITE_FAIL;
    }
    es8389_pa_power(codec, ES_PA_SETUP | ES_PA_ENABLE);
    codec->is_open = true;
    return ESP_CODEC_DEV_OK;
}

static int es8389_close(const audio_codec_if_t *h)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;
    if (codec == NULL) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    if (codec->is_open) {
        es8389_pa_power(codec, ES_PA_DISABLE);
        es8389_suspend(codec);
        codec->is_open = false;
    }
    return ESP_CODEC_DEV_OK;
}

static int es8389_set_fs(const audio_codec_if_t *h, esp_codec_dev_sample_info_t *fs)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;
    if (codec == NULL || codec->is_open == false) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }

    if (!codec->use_mclk) {
        es8389_config_sample(codec, fs->sample_rate,fs->bits_per_sample);
    }

    es8389_set_bits_per_sample(codec, fs->bits_per_sample);
    es8389_config_fmt(codec, ES_I2S_NORMAL);
    es8389_set_bias_standby(codec);
    es8389_set_bias_on(codec);
    return ESP_CODEC_DEV_OK;
}

static int es8389_enable(const audio_codec_if_t *h, bool enable)
{
    int ret = ESP_CODEC_DEV_OK;
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;
    if (codec == NULL) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    if (codec->is_open == false) {
        return ESP_CODEC_DEV_WRONG_STATE;
    }
    if (enable == codec->enabled) {
        return ESP_CODEC_DEV_OK;
    }
    if (enable) {
        ret = es8389_start(codec);
        es8389_pa_power(codec, ES_PA_ENABLE);
    } else {
        es8389_pa_power(codec, ES_PA_DISABLE);
        ret = es8389_suspend(codec);
    }
    if (ret == ESP_CODEC_DEV_OK) {
        codec->enabled = enable;
        ESP_LOGD(TAG, "Codec is %s", enable ? "enabled" : "disabled");
    }
    return ret;
}

static int es8389_set_reg(const audio_codec_if_t *h, int reg, int value)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;
    if (codec == NULL) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    if (codec->is_open == false) {
        return ESP_CODEC_DEV_WRONG_STATE;
    }
    return es8389_write_reg(codec, reg, value);
}

static int es8389_get_reg(const audio_codec_if_t *h, int reg, int *value)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;
    if (codec == NULL) {
        return ESP_CODEC_DEV_INVALID_ARG;
    }
    if (codec->is_open == false) {
        return ESP_CODEC_DEV_WRONG_STATE;
    }
    return es8389_read_reg(codec, reg, value);
}

static void es8389_dump(const audio_codec_if_t *h)
{
    audio_codec_es8389_t *codec = (audio_codec_es8389_t *) h;
    if (codec == NULL || codec->is_open == false) {
        return;
    }
    for (int i = 0; i < ES8389_MAX_REGISTER; i++) {
        int value = 0;
        int ret = es8389_read_reg(codec, i, &value);
        if (ret != ESP_CODEC_DEV_OK) {
            break;
        }
        ESP_LOGI(TAG, "%02x: %02x", i, value);
    }
}

const audio_codec_if_t *es8389_codec_new(es8389_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_es8389_t *codec = (audio_codec_es8389_t *) calloc(1, sizeof(audio_codec_es8389_t));
    if (codec == NULL) {
        CODEC_MEM_CHECK(codec);
        return NULL;
    }
    codec->base.open = es8389_open;
    codec->base.enable = es8389_enable;
    codec->base.set_fs = es8389_set_fs;
    codec->base.set_vol = es8389_set_vol;
    codec->base.set_mic_gain = es8389_set_mic_gain;
    codec->base.mute = es8389_set_mute;
    codec->base.set_reg = es8389_set_reg;
    codec->base.get_reg = es8389_get_reg;
    codec->base.dump_reg = es8389_dump;
    codec->base.close = es8389_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(es8389_codec_cfg_t));
        if (ret != 0) {
            ESP_LOGE(TAG, "Open fail");
            break;
        }
        return &codec->base;
    } while (0);
    if (codec) {
        free(codec);
    }
    return NULL;
}
