Compare commits

...

1 Commits

Author SHA1 Message Date
Adolfo Reyna 7788415e0e feat(es8311): add digital input gain and restore 42dB HW max for ES3C28P/35P
- Same as firmware: add input-gain-percent, 42dB HW max, digital multiplier
2026-07-31 12:11:13 -04:00
5 changed files with 34 additions and 4 deletions
+1
View File
@@ -91,6 +91,7 @@
compatible = "everest,es8311"; compatible = "everest,es8311";
reg = <0x18>; reg = <0x18>;
i2s = <&i2s0>; i2s = <&i2s0>;
input-gain-percent = <100>;
}; };
}; };
+1
View File
@@ -88,6 +88,7 @@
compatible = "everest,es8311"; compatible = "everest,es8311";
reg = <0x18>; reg = <0x18>;
i2s = <&i2s0>; i2s = <&i2s0>;
input-gain-percent = <100>;
}; };
}; };
@@ -9,3 +9,7 @@ properties:
type: phandle type: phandle
required: true required: true
description: "I2S controller device that carries audio data" description: "I2S controller device that carries audio data"
input-gain-percent:
type: int
default: 100
description: "Extra digital gain multiplier applied by audio_stream on top of the ES8311's own 24dB hardware ADC gain, as an integer percentage (100 = 1.0x / no extra boost). For quiet MEMS mic capsules that are still quiet even at max hardware gain."
@@ -25,6 +25,14 @@ struct Es8311Config {
uint8_t address; uint8_t address;
/** I2S controller device that carries audio data */ /** I2S controller device that carries audio data */
struct Device* i2s_device; struct Device* i2s_device;
/**
* Extra fixed digital gain multiplier applied by audio_stream on top of the ES8311's
* own hardware ADC gain (0..24dB), as an integer percentage (100 = 1.0x / no extra boost).
* Small MEMS mic capsules can still sound quiet even near max hardware gain; this is for
* boards where 24dB hardware gain alone isn't enough. devicetree has no float property type,
* hence the x100 integer encoding.
*/
uint16_t input_gain_percent;
}; };
#ifdef __cplusplus #ifdef __cplusplus
+20 -4
View File
@@ -31,6 +31,7 @@ struct Es8311Data {
bool is_open = false; bool is_open = false;
AudioCodecDirection open_direction = AUDIO_CODEC_DIR_BOTH; AudioCodecDirection open_direction = AUDIO_CODEC_DIR_BOTH;
esp_codec_dev_sample_info_t open_sample_info = {}; esp_codec_dev_sample_info_t open_sample_info = {};
float input_gain = 1.0f;
}; };
#define GET_CONFIG(device) (static_cast<const Es8311Config*>((device)->config)) #define GET_CONFIG(device) (static_cast<const Es8311Config*>((device)->config))
@@ -164,8 +165,8 @@ error_t set_volume(Device* device, AudioCodecDirection direction, float volume_p
} }
if (direction == AUDIO_CODEC_DIR_INPUT) { if (direction == AUDIO_CODEC_DIR_INPUT) {
// ES8311 ADC gain range is roughly 0..24 dB; map 0..100% linearly onto it. // ES8311 ADC gain supports 0..42dB (0,6,12,18,24,30,36,42) – max hardware to restore old +30dB+ behavior
float db = (volume_percent / 100.0f) * 24.0f; float db = (volume_percent / 100.0f) * 42.0f;
return (esp_codec_dev_set_in_gain(data->codec_device, db) == ESP_CODEC_DEV_OK) ? ERROR_NONE : ERROR_RESOURCE; return (esp_codec_dev_set_in_gain(data->codec_device, db) == ESP_CODEC_DEV_OK) ? ERROR_NONE : ERROR_RESOURCE;
} }
@@ -192,7 +193,8 @@ error_t get_volume(Device* device, AudioCodecDirection direction, float* volume_
if (esp_codec_dev_get_in_gain(data->codec_device, &db) != ESP_CODEC_DEV_OK) { if (esp_codec_dev_get_in_gain(data->codec_device, &db) != ESP_CODEC_DEV_OK) {
return ERROR_RESOURCE; return ERROR_RESOURCE;
} }
*volume_percent = (db / 24.0f) * 100.0f; *volume_percent = (db / 42.0f) * 100.0f;
if (*volume_percent > 100.0f) *volume_percent = 100.0f;
return ERROR_NONE; return ERROR_NONE;
} }
@@ -255,6 +257,12 @@ error_t get_capabilities(Device* device, AudioCodecDirection* supported_directio
return ERROR_NONE; return ERROR_NONE;
} }
error_t get_input_gain_multiplier(Device* device, float* gain) {
auto* data = GET_DATA(device);
*gain = data->input_gain;
return ERROR_NONE;
}
static const struct AudioCodecApi API = { static const struct AudioCodecApi API = {
.open = open, .open = open,
.close = close, .close = close,
@@ -267,7 +275,7 @@ static const struct AudioCodecApi API = {
.get_native_sample_rate = get_native_sample_rate, .get_native_sample_rate = get_native_sample_rate,
.get_native_channels = get_native_channels, .get_native_channels = get_native_channels,
.get_capabilities = get_capabilities, .get_capabilities = get_capabilities,
.get_input_gain_multiplier = nullptr, .get_input_gain_multiplier = get_input_gain_multiplier,
}; };
// endregion // endregion
@@ -277,6 +285,11 @@ static const struct AudioCodecApi API = {
error_t start_device(Device* device) { error_t start_device(Device* device) {
const auto* config = GET_CONFIG(device); const auto* config = GET_CONFIG(device);
if (config->input_gain_percent > 2000) {
LOG_E(TAG, "Invalid input_gain_percent %u (must be 0..2000)", config->input_gain_percent);
return ERROR_RESOURCE;
}
auto* i2c_controller = device_get_parent(device); auto* i2c_controller = device_get_parent(device);
if (i2c_controller == nullptr || device_get_type(i2c_controller) != &I2C_CONTROLLER_TYPE) { if (i2c_controller == nullptr || device_get_type(i2c_controller) != &I2C_CONTROLLER_TYPE) {
LOG_E(TAG, "Parent is not an I2C controller"); LOG_E(TAG, "Parent is not an I2C controller");
@@ -290,6 +303,9 @@ error_t start_device(Device* device) {
} }
auto* data = new Es8311Data(); auto* data = new Es8311Data();
data->input_gain = (float) config->input_gain_percent / 100.0f;
if (data->input_gain < 0.0f) data->input_gain = 1.0f;
if (config->input_gain_percent == 0) data->input_gain = 1.0f; // default when not set (devicetree default 100, but 0 means unset)
data->ctrl_if = audio_codec_adapter_new_i2c_ctrl(i2c_controller, config->address); data->ctrl_if = audio_codec_adapter_new_i2c_ctrl(i2c_controller, config->address);
data->data_if = audio_codec_adapter_new_i2s_data(i2s_controller); data->data_if = audio_codec_adapter_new_i2s_data(i2s_controller);