Files
pi-dashboard/components/ExternLib/codec_board/codec_init.c
Mikkeli Matlock 19db125619 initial commit
2026-02-15 02:48:59 +09:00

711 lines
23 KiB
C

#include <string.h>
#include <stdint.h>
#include "driver/i2c.h"
#include "esp_idf_version.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "driver/i2s_std.h"
#include "driver/i2s_tdm.h"
#include "driver/i2s_pdm.h"
#include "soc/soc_caps.h"
#else
#include "driver/i2s.h"
#endif
#include "esp_codec_dev.h"
#include "esp_codec_dev_defaults.h"
#include "esp_codec_dev_os.h"
#include "codec_board.h"
#include "codec_init.h"
#include "esp_log.h"
#include "dummy_codec.h"
#include "driver/i2c_master.h"
#include "esp_vfs_fat.h"
#include "driver/sdmmc_host.h"
#include "driver/sdmmc_defs.h"
#define TAG "CODEC_INIT"
typedef struct {
bool inited;
const audio_codec_data_if_t *data_if;
const audio_codec_data_if_t *data_in_if;
const audio_codec_gpio_if_t *gpio_if;
const audio_codec_ctrl_if_t *in_ctrl_if;
const audio_codec_ctrl_if_t *out_ctrl_if;
const audio_codec_if_t *out_codec_if;
const audio_codec_if_t *in_codec_if;
esp_codec_dev_handle_t play_dev;
esp_codec_dev_handle_t record_dev;
} codec_res_t;
#define USE_I2C_MASTER
typedef struct {
bool inited;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
i2s_chan_handle_t tx_handle;
i2s_chan_handle_t rx_handle;
#endif
} i2s_keep_t;
static bool i2c_inited[MAX_I2C_NUM];
static i2c_master_bus_handle_t i2c_bus_handle[MAX_I2C_NUM];
static i2s_keep_t *i2s_keep[MAX_I2S_NUM];
static codec_res_t codec_res;
static int _i2c_init(uint8_t port)
{
if (port >= MAX_I2C_NUM) {
return -1;
}
if (i2c_inited[port]) {
return 0;
}
codec_i2c_pin_t i2c_pin;
if (get_i2c_pin(port, &i2c_pin)) {
ESP_LOGE(TAG, "Fail to get i2c pin");
return -1;
}
// workaround to check i2c initialized already
int ret = 0;
#ifdef USE_I2C_MASTER
i2c_master_bus_config_t i2c_bus_config = { 0 };
i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
i2c_bus_config.i2c_port = port;
i2c_bus_config.scl_io_num = i2c_pin.scl;
i2c_bus_config.sda_io_num = i2c_pin.sda;
i2c_bus_config.glitch_ignore_cnt = 7;
i2c_bus_config.flags.enable_internal_pullup = true;
ret = i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle[port]);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "failed to initialize I2C master bus port %d", port);
return -1;
}
ESP_LOGI(TAG, "Set mater handle %d %p", port, i2c_bus_handle[port]);
#else
i2c_config_t i2c_cfg = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
i2c_cfg.sda_io_num = i2c_pin.sda;
i2c_cfg.scl_io_num = i2c_pin.scl;
ret = i2c_param_config(port, &i2c_cfg);
if (ret != ESP_OK) {
return -1;
}
ret = i2c_driver_install(port, i2c_cfg.mode, 0, 0, 0);
#endif
if (ret == 0) {
i2c_inited[port] = true;
}
return ret;
}
void *get_i2c_bus_handle(uint8_t port)
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
// Try to get port from I2C driver directly
i2c_master_bus_handle_t bus_handle = NULL;
i2c_master_get_bus_handle(port, &bus_handle);
return bus_handle;
#endif
return i2c_bus_handle[port];
}
static int _i2c_deinit(uint8_t port)
{
if (port >= MAX_I2C_NUM || i2c_inited[port] == false) {
return -1;
}
#ifdef USE_I2C_MASTER
i2c_del_master_bus(i2c_bus_handle[port]);
#else
i2c_driver_delete(port);
#endif
i2c_bus_handle[port] = NULL;
i2c_inited[port] = false;
return 0;
}
static int _i2s_init(uint8_t port, esp_codec_dev_type_t dev_type, codec_init_cfg_t *init_cfg)
{
if (port >= MAX_I2S_NUM) {
return -1;
}
if (i2s_keep[port]) {
return 0;
}
codec_i2s_pin_t i2s_cfg;
if (get_i2s_pin(port, &i2s_cfg)) {
ESP_LOGE(TAG, "Fail to get i2s pin");
return -1;
}
ESP_LOGI(TAG, "Init i2s %d type: %d mclk:%d bclk:%d ws:%d din:%d dout:%d",
port, dev_type, i2s_cfg.mclk,
i2s_cfg.bclk, i2s_cfg.ws, i2s_cfg.din, i2s_cfg.dout);
i2s_keep[port] = (i2s_keep_t *)calloc(1, sizeof(i2s_keep_t));
if (i2s_keep[port] == NULL) {
return -1;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
chan_cfg.auto_clear = true;
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000),
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(32, I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.mclk = i2s_cfg.mclk,
.bclk = i2s_cfg.bclk,
.ws = i2s_cfg.ws,
.dout = i2s_cfg.dout,
.din = i2s_cfg.din,
},
};
bool output = (dev_type & ESP_CODEC_DEV_TYPE_OUT) > 0;
bool input = (dev_type & ESP_CODEC_DEV_TYPE_IN) > 0;
// Same I2S have tx and rx but use rx or tx only
if (output && init_cfg->out_mode == CODEC_I2S_MODE_NONE) {
output = false;
}
if (input && init_cfg->in_mode == CODEC_I2S_MODE_NONE) {
input = false;
}
if (input == false && output == false) {
return 0;
}
#ifdef SOC_I2S_SUPPORTS_TDM
i2s_tdm_slot_mask_t slot_mask = I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3;
i2s_tdm_config_t tdm_cfg = {
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(32, I2S_SLOT_MODE_STEREO, slot_mask),
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(16000),
.gpio_cfg = {
.mclk = i2s_cfg.mclk,
.bclk = i2s_cfg.bclk,
.ws = i2s_cfg.ws,
.dout = i2s_cfg.dout,
.din = i2s_cfg.din,
},
};
tdm_cfg.slot_cfg.total_slot = 4;
#endif
chan_cfg.id = I2S_NUM_AUTO; // Use auto ID
int ret = i2s_new_channel(&chan_cfg, output == false ? NULL : &i2s_keep[port]->tx_handle,
input == false ? NULL : &i2s_keep[port]->rx_handle);
ESP_LOGI(TAG, "tx:%p rx:%p", i2s_keep[port]->tx_handle, i2s_keep[port]->rx_handle);
if (i2s_keep[port]->tx_handle) {
if (init_cfg->out_mode == CODEC_I2S_MODE_STD) {
ret = i2s_channel_init_std_mode(i2s_keep[port]->tx_handle, &std_cfg);
ESP_LOGI(TAG, "output init std ret %d", ret);
}
#ifdef SOC_I2S_SUPPORTS_TDM
else if (init_cfg->out_mode == CODEC_I2S_MODE_TDM) {
ret = i2s_channel_init_tdm_mode(i2s_keep[port]->tx_handle, &tdm_cfg);
ESP_LOGI(TAG, "output init tdm ret %d", ret);
}
#endif
#ifdef SOC_I2S_SUPPORTS_PDM_TX
else if (init_cfg->out_mode == CODEC_I2S_MODE_PDM) {
i2s_pdm_tx_config_t pdm_cfg = {
.clk_cfg = I2S_PDM_TX_CLK_DEFAULT_CONFIG(16000),
.slot_cfg = I2S_PDM_TX_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.dout = i2s_cfg.dout,
.clk = i2s_cfg.bclk,
.invert_flags = {
.clk_inv = false,
},
},
};
ret = i2s_channel_init_pdm_tx_mode(i2s_keep[port]->tx_handle, &pdm_cfg);
ESP_LOGI(TAG, "output init pdm ret %d", ret);
}
#endif
}
if (i2s_keep[port]->rx_handle) {
if (init_cfg->in_mode == CODEC_I2S_MODE_STD) {
ret = i2s_channel_init_std_mode(i2s_keep[port]->rx_handle, &std_cfg);
ESP_LOGI(TAG, "Input init std ret %d", ret);
}
#ifdef SOC_I2S_SUPPORTS_TDM
else if (init_cfg->in_mode == CODEC_I2S_MODE_TDM) {
ret = i2s_channel_init_tdm_mode(i2s_keep[port]->rx_handle, &tdm_cfg);
ESP_LOGI(TAG, "Input init tdm ret %d", ret);
}
#endif
#ifdef SOC_I2S_SUPPORTS_PDM_RX
else if (init_cfg->in_mode == CODEC_I2S_MODE_PDM) {
i2s_pdm_rx_config_t pdm_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(16000),
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.din = i2s_cfg.din,
.clk = i2s_cfg.bclk,
.invert_flags = {
.clk_inv = false,
},
},
};
ret = i2s_channel_init_pdm_rx_mode(i2s_keep[port]->rx_handle, &pdm_cfg);
ESP_LOGI(TAG, "Input init pdm ret %d", ret);
}
#endif
}
// Enable I2S here for maybe some codec need I2S clock to set register correctly
if (i2s_keep[port]->tx_handle) {
i2s_channel_enable(i2s_keep[port]->tx_handle);
}
if (i2s_keep[port]->rx_handle) {
i2s_channel_enable(i2s_keep[port]->rx_handle);
}
#else
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2 | ESP_INTR_FLAG_IRAM,
.dma_buf_count = 3,
.dma_buf_len = 300,
.use_apll = true,
.tx_desc_auto_clear = true,
.fixed_mclk = 0
//.mclk_multiple = 256,
};
int ret = i2s_driver_install(port, &i2s_config, 0, NULL);
i2s_pin_config_t i2s_pin_cfg = {
.mck_io_num = i2s_cfg.mclk,
.bck_io_num = i2s_cfg.bclk,
.ws_io_num = i2s_cfg.ws,
.data_out_num = i2s_cfg.dout,
.data_in_num = i2s_cfg.din,
};
i2s_set_pin(port, &i2s_pin_cfg);
#endif
ESP_LOGI(TAG, "Init i2s %d ok", port);
i2s_keep[port]->inited = true;
return ret;
}
static int _i2s_deinit(uint8_t port)
{
if (port >= MAX_I2S_NUM) {
return -1;
}
if (i2s_keep[port] == NULL) {
return 0;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
if (i2s_keep[port]->tx_handle) {
i2s_channel_disable(i2s_keep[port]->tx_handle);
}
if (i2s_keep[port]->rx_handle) {
i2s_channel_disable(i2s_keep[port]->rx_handle);
}
if (i2s_keep[port]->tx_handle) {
i2s_del_channel(i2s_keep[port]->tx_handle);
}
if (i2s_keep[port]->rx_handle) {
i2s_del_channel(i2s_keep[port]->rx_handle);
}
#else
i2s_driver_uninstall(port);
#endif
free(i2s_keep[port]);
i2s_keep[port] = NULL;
return 0;
}
int init_i2c(uint8_t port)
{
return _i2c_init(port);
}
int deinit_i2c(uint8_t port)
{
return _i2c_deinit(port);
}
static int check_i2c_inited(int8_t port)
{
if (port < 0) {
return 0;
}
// Already installed
if (get_i2c_bus_handle(port)) {
return 0;
}
return _i2c_init(port);
}
int init_codec(codec_init_cfg_t *cfg)
{
if (cfg == NULL) {
return -1;
}
if (codec_res.inited) {
ESP_LOGI(TAG, "Already initialized");
return 0;
}
codec_cfg_t out_cfg = { 0 };
codec_cfg_t in_cfg = { 0 };
bool has_out = false;
bool has_in = false;
// Get codec configuration
if (get_out_codec_cfg(&out_cfg) == 0) {
has_out = true;
}
if (get_in_codec_cfg(&in_cfg) == 0) {
has_in = true;
}
if (has_out == false && has_in == false) {
ESP_LOGE(TAG, "No codec device found");
return -1;
}
// Try to get I2C handle
check_i2c_inited(0);
// Init i2c and i2s
bool same_i2s = (has_in && has_out && out_cfg.i2s_port == in_cfg.i2s_port);
ESP_LOGI(TAG, "in:%d out:%d port: %d", has_in, has_out, out_cfg.i2s_port == in_cfg.i2s_port);
if (has_out) {
if (check_i2c_inited(out_cfg.i2c_port) < 0) {
ESP_LOGE(TAG, "Fail to int i2c: %d", out_cfg.i2c_port);
return -1;
}
ESP_LOGI(TAG, "Success to int i2c: %d", in_cfg.i2c_port);
if (_i2s_init(out_cfg.i2s_port, same_i2s ? ESP_CODEC_DEV_TYPE_IN_OUT : ESP_CODEC_DEV_TYPE_OUT, cfg)) {
ESP_LOGE(TAG, "Fail to init i2s: %d", out_cfg.i2s_port);
return -1;
}
ESP_LOGI(TAG, "Success to init i2s: %d", in_cfg.i2s_port);
}
if (has_in) {
if (check_i2c_inited(in_cfg.i2c_port) < 0) {
ESP_LOGE(TAG, "Fail to int i2c: %d", in_cfg.i2c_port);
return -1;
}
ESP_LOGI(TAG, "Success to int i2c: %d", in_cfg.i2c_port);
if (_i2s_init(in_cfg.i2s_port, same_i2s ? ESP_CODEC_DEV_TYPE_IN_OUT : ESP_CODEC_DEV_TYPE_IN, cfg)) {
ESP_LOGE(TAG, "Fail to init i2s: %d", in_cfg.i2s_port);
return -1;
}
ESP_LOGI(TAG, "Success to init i2s: %d", in_cfg.i2s_port);
}
// Create gpio interface
codec_res.gpio_if = audio_codec_new_gpio();
bool same_codec = same_i2s && (in_cfg.codec_type == out_cfg.codec_type);
if (has_out) {
audio_codec_i2s_cfg_t i2s_out_cfg = {
.port = out_cfg.i2s_port,
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
.tx_handle = i2s_keep[out_cfg.i2s_port]->tx_handle,
.rx_handle = i2s_keep[out_cfg.i2s_port]->rx_handle,
#endif
};
ESP_LOGI(TAG, "Get out handle %p port %d", i2s_out_cfg.tx_handle, out_cfg.i2s_port);
codec_res.data_if = audio_codec_new_i2s_data(&i2s_out_cfg);
audio_codec_i2c_cfg_t i2c_cfg = {
.port = out_cfg.i2c_port,
#ifdef USE_I2C_MASTER
.bus_handle = get_i2c_bus_handle(out_cfg.i2c_port),
#endif
};
// TODO add other codec support
switch (out_cfg.codec_type) {
case CODEC_TYPE_ES8311: {
i2c_cfg.addr = out_cfg.i2c_addr ? out_cfg.i2c_addr : ES8311_CODEC_DEFAULT_ADDR;
codec_res.out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
es8311_codec_cfg_t es8311_cfg = {
.codec_mode = same_codec ? ESP_CODEC_DEV_WORK_MODE_BOTH : ESP_CODEC_DEV_WORK_MODE_DAC,
.ctrl_if = codec_res.out_ctrl_if,
.gpio_if = codec_res.gpio_if,
.pa_pin = out_cfg.pa_pin,
.use_mclk = out_cfg.use_mclk,
.hw_gain.pa_gain = out_cfg.pa_gain,
};
codec_res.out_codec_if = es8311_codec_new(&es8311_cfg);
} break;
case CODEC_TYPE_ES8388: {
i2c_cfg.addr = out_cfg.i2c_addr ? out_cfg.i2c_addr : ES8388_CODEC_DEFAULT_ADDR;
codec_res.out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
es8388_codec_cfg_t es8388_cfg = {
.codec_mode = same_codec ? ESP_CODEC_DEV_WORK_MODE_BOTH : ESP_CODEC_DEV_WORK_MODE_DAC,
.ctrl_if = codec_res.out_ctrl_if,
.gpio_if = codec_res.gpio_if,
.pa_pin = out_cfg.pa_pin,
.hw_gain.pa_gain = out_cfg.pa_gain,
};
codec_res.out_codec_if = es8388_codec_new(&es8388_cfg);
} break;
case CODEC_TYPE_DUMMY: {
dummy_codec_cfg_t dummy_cfg = {
.gpio_if = codec_res.gpio_if,
.enable_gpio = out_cfg.pa_pin,
};
codec_res.out_codec_if = dummy_codec_new(&dummy_cfg);
} break;
default:
ESP_LOGE(TAG, "TODO not supported output codec type %d", out_cfg.codec_type);
break;
}
esp_codec_dev_cfg_t dev_cfg = {
.codec_if = codec_res.out_codec_if,
.data_if = codec_res.data_if,
.dev_type = ESP_CODEC_DEV_TYPE_OUT,
};
if (same_codec && cfg->reuse_dev) {
dev_cfg.dev_type = ESP_CODEC_DEV_TYPE_IN_OUT;
}
codec_res.play_dev = esp_codec_dev_new(&dev_cfg);
if (same_codec) {
if (cfg->reuse_dev) {
codec_res.record_dev = codec_res.play_dev;
} else {
// separate record from playback so that can set different fs
dev_cfg.dev_type = ESP_CODEC_DEV_TYPE_IN;
codec_res.record_dev = esp_codec_dev_new(&dev_cfg);
}
}
}
if (same_codec == false && has_in) {
if (same_i2s == false) {
audio_codec_i2s_cfg_t i2s_in_cfg = {
.port = in_cfg.i2s_port,
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
.rx_handle = i2s_keep[in_cfg.i2s_port]->rx_handle,
#endif
};
ESP_LOGI(TAG, "Get in handle %p port %d", i2s_in_cfg.rx_handle, i2s_in_cfg.port);
codec_res.data_in_if = audio_codec_new_i2s_data(&i2s_in_cfg);
}
audio_codec_i2c_cfg_t i2c_cfg = {
.port = in_cfg.i2c_port,
#ifdef USE_I2C_MASTER
.bus_handle = get_i2c_bus_handle(in_cfg.i2c_port),
#endif
};
// TODO add other codec support
switch (in_cfg.codec_type) {
case CODEC_TYPE_ES7210: {
i2c_cfg.addr = in_cfg.i2c_addr ? in_cfg.i2c_addr : ES7210_CODEC_DEFAULT_ADDR;
codec_res.in_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
es7210_codec_cfg_t es7210_cfg = {
.ctrl_if = codec_res.in_ctrl_if,
.mic_selected = ES7210_SEL_MIC1 | ES7210_SEL_MIC3,
};
if (cfg->in_use_tdm || (cfg->in_mode == CODEC_I2S_MODE_TDM)) {
es7210_cfg.mic_selected |= ES7210_SEL_MIC2 | ES7210_SEL_MIC4;
}
codec_res.in_codec_if = es7210_codec_new(&es7210_cfg);
} break;
case CODEC_TYPE_ES7243: {
i2c_cfg.addr = in_cfg.i2c_addr ? in_cfg.i2c_addr : ES7243_CODEC_DEFAULT_ADDR;
codec_res.in_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
es7243_codec_cfg_t es7243_cfg = {
.ctrl_if = codec_res.in_ctrl_if,
};
codec_res.in_codec_if = es7243_codec_new(&es7243_cfg);
} break;
case CODEC_TYPE_DUMMY: {
dummy_codec_cfg_t dummy_cfg = {
.gpio_if = codec_res.gpio_if,
.enable_gpio = out_cfg.pa_pin,
};
codec_res.in_codec_if = dummy_codec_new(&dummy_cfg);
}
default:
break;
}
esp_codec_dev_cfg_t dev_cfg = {
.codec_if = codec_res.in_codec_if,
.data_if = same_i2s ? codec_res.data_if : codec_res.data_in_if,
.dev_type = ESP_CODEC_DEV_TYPE_IN,
};
codec_res.record_dev = esp_codec_dev_new(&dev_cfg);
}
// Set default volume and gain for play and record
if (codec_res.play_dev) {
esp_codec_dev_set_out_vol(codec_res.play_dev, 60.0);
}
if (codec_res.record_dev) {
esp_codec_dev_set_in_gain(codec_res.record_dev, 30.0);
}
if ((codec_res.play_dev != NULL) || (codec_res.record_dev != NULL)) {
codec_res.inited = true;
return 0;
}
return -1;
}
esp_codec_dev_handle_t get_playback_handle(void)
{
return codec_res.play_dev;
}
esp_codec_dev_handle_t get_record_handle(void)
{
return codec_res.record_dev;
}
void deinit_codec(void)
{
if (codec_res.play_dev) {
esp_codec_dev_delete(codec_res.play_dev);
if (codec_res.record_dev == codec_res.play_dev) {
codec_res.record_dev = NULL;
}
codec_res.play_dev = NULL;
}
if (codec_res.record_dev) {
esp_codec_dev_delete(codec_res.record_dev);
codec_res.record_dev = NULL;
}
// Delete codec interface
if (codec_res.in_codec_if) {
audio_codec_delete_codec_if(codec_res.in_codec_if);
codec_res.in_codec_if = NULL;
}
if (codec_res.out_codec_if) {
audio_codec_delete_codec_if(codec_res.out_codec_if);
codec_res.out_codec_if = NULL;
}
// Delete codec control interface
if (codec_res.in_ctrl_if) {
audio_codec_delete_ctrl_if(codec_res.in_ctrl_if);
codec_res.in_ctrl_if = NULL;
}
if (codec_res.out_ctrl_if) {
audio_codec_delete_ctrl_if(codec_res.out_ctrl_if);
codec_res.out_ctrl_if = NULL;
}
if (codec_res.data_if) {
audio_codec_delete_data_if(codec_res.data_if);
codec_res.data_if = NULL;
}
if (codec_res.data_in_if) {
audio_codec_delete_data_if(codec_res.data_in_if);
codec_res.data_in_if = NULL;
}
if (codec_res.gpio_if) {
audio_codec_delete_gpio_if(codec_res.gpio_if);
codec_res.gpio_if = NULL;
}
for (int i = 0; i < MAX_I2C_NUM; i++) {
_i2c_deinit(i);
_i2s_deinit(i);
}
codec_res.inited = false;
}
static sdmmc_card_t *card = NULL;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
#if CONFIG_IDF_TARGET_ESP32P4
#include "esp_ldo_regulator.h"
#endif
#endif
static void enable_mmc_phy_power(void)
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
#if CONFIG_IDF_TARGET_ESP32P4
esp_ldo_channel_config_t ldo_cfg = {
.chan_id = 4,
.voltage_mv = 3300,
};
esp_ldo_channel_handle_t ldo_phy_chan;
esp_ldo_acquire_channel(&ldo_cfg, &ldo_phy_chan);
#endif
#endif
}
#if CONFIG_IDF_TARGET_ESP32P4
static void sdmmc_get_slot(const int slot, sdmmc_slot_config_t *config)
{
memset(config, 0, sizeof(sdmmc_slot_config_t));
config->cd = SDMMC_SLOT_NO_CD;
config->wp = SDMMC_SLOT_NO_WP;
config->width = 4;
config->flags = 0;
}
#endif
int mount_sdcard(void)
{
sdcard_cfg_t cfg = { 0 };
enable_mmc_phy_power();
int ret = get_sdcard_config(&cfg);
if (ret != 0) {
return ret;
}
#if defined CONFIG_IDF_TARGET_ESP32
gpio_config_t sdcard_pwr_pin_cfg = {
.pin_bit_mask = 1UL << GPIO_NUM_13,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&sdcard_pwr_pin_cfg);
gpio_set_level(GPIO_NUM_13, 0);
#endif
#if SOC_SDMMC_HOST_SUPPORTED
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 5,
};
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
#if CONFIG_IDF_TARGET_ESP32P4
host.slot = 0;
#endif
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
#endif
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
slot_config.width = cfg.d3 ? 4 : 1;
#if SOC_SDMMC_USE_GPIO_MATRIX
slot_config.width = cfg.d3 ? 4 : 1;
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
slot_config.d4 = -1;
slot_config.d5 = -1;
slot_config.d6 = -1;
slot_config.d7 = -1;
slot_config.cd = -1;
slot_config.wp = -1;
slot_config.clk = cfg.clk;
slot_config.cmd = cfg.cmd;
slot_config.d0 = cfg.d0;
slot_config.d1 = cfg.d1 ? cfg.d1 : -1;
slot_config.d2 = cfg.d2 ? cfg.d2 : -1;
slot_config.d3 = cfg.d3 ? cfg.d3 : -1;
#endif /* SOC_SDMMC_USE_GPIO_MATRIX */
#if CONFIG_IDF_TARGET_ESP32P4
sdmmc_get_slot(0, &slot_config);
#endif
printf("use %d %d %d %d\n", cfg.d0, cfg.d1, cfg.d2, cfg.d3);
return esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
#else
return -1;
#endif
}
void *get_sdcard_handle(void)
{
return card;
}
void unmount_sdcard(void)
{
if (card) {
esp_vfs_fat_sdcard_unmount("/sdcard", card);
card = NULL;
}
}