diff --git a/esphome/components/es8156/audio_dac.py b/esphome/components/es8156/audio_dac.py index b9d8eae6b0..a805fb3f70 100644 --- a/esphome/components/es8156/audio_dac.py +++ b/esphome/components/es8156/audio_dac.py @@ -2,11 +2,14 @@ import esphome.codegen as cg from esphome.components import i2c from esphome.components.audio_dac import AudioDac import esphome.config_validation as cv -from esphome.const import CONF_ID +from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID +import esphome.final_validate as fv CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["i2c"] +CONF_AUDIO_DAC = "audio_dac" + es8156_ns = cg.esphome_ns.namespace("es8156") ES8156 = es8156_ns.class_("ES8156", AudioDac, cg.Component, i2c.I2CDevice) @@ -21,6 +24,29 @@ CONFIG_SCHEMA = ( ) +def _final_validate(config): + full_config = fv.full_config.get() + + # Check all speaker configurations for ones that reference this es8156 + speaker_configs = full_config.get("speaker", []) + for speaker_config in speaker_configs: + audio_dac_id = speaker_config.get(CONF_AUDIO_DAC) + if ( + audio_dac_id is not None + and audio_dac_id == config[CONF_ID] + and (bits_per_sample := speaker_config.get(CONF_BITS_PER_SAMPLE)) + is not None + and bits_per_sample > 24 + ): + raise cv.Invalid( + f"ES8156 does not support more than 24 bits per sample. " + f"The speaker referencing this audio_dac has bits_per_sample set to {bits_per_sample}." + ) + + +FINAL_VALIDATE_SCHEMA = _final_validate + + async def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/es8156/es8156.cpp b/esphome/components/es8156/es8156.cpp index e84252efe2..961dc24b29 100644 --- a/esphome/components/es8156/es8156.cpp +++ b/esphome/components/es8156/es8156.cpp @@ -17,24 +17,61 @@ static const char *const TAG = "es8156"; } void ES8156::setup() { + // REG02 MODE CONFIG 1: Enable software mode for I2C control of volume/mute + // Bit 2: SOFT_MODE_SEL=1 (software mode enabled) ES8156_ERROR_FAILED(this->write_byte(ES8156_REG02_SCLK_MODE, 0x04)); + + // Analog system configuration (active-low power down bits, active-high enables) + // REG20 ANALOG SYSTEM: Configure analog signal path ES8156_ERROR_FAILED(this->write_byte(ES8156_REG20_ANALOG_SYS1, 0x2A)); + + // REG21 ANALOG SYSTEM: VSEL=0x1C (bias level ~120%), normal VREF ramp speed ES8156_ERROR_FAILED(this->write_byte(ES8156_REG21_ANALOG_SYS2, 0x3C)); + + // REG22 ANALOG SYSTEM: Line out mode (HPSW=0), OUT_MUTE=0 (not muted) ES8156_ERROR_FAILED(this->write_byte(ES8156_REG22_ANALOG_SYS3, 0x00)); + + // REG24 ANALOG SYSTEM: Low power mode for VREFBUF, HPCOM, DACVRP; DAC normal power + // Bits 2:0 = 0x07: LPVREFBUF=1, LPHPCOM=1, LPDACVRP=1, LPDAC=0 ES8156_ERROR_FAILED(this->write_byte(ES8156_REG24_ANALOG_LP, 0x07)); + + // REG23 ANALOG SYSTEM: Lowest bias (IBIAS_SW=0), VMIDLVL=VDDA/2, normal impedance ES8156_ERROR_FAILED(this->write_byte(ES8156_REG23_ANALOG_SYS4, 0x00)); + // Timing and interface configuration + // REG0A/0B TIME CONTROL: Fast state machine transitions ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0A_TIME_CONTROL1, 0x01)); ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0B_TIME_CONTROL2, 0x01)); + + // REG11 SDP INTERFACE CONFIG: Default I2S format (24-bit, I2S mode) ES8156_ERROR_FAILED(this->write_byte(ES8156_REG11_DAC_SDP, 0x00)); + + // REG19 EQ CONTROL 1: EQ disabled (EQ_ON=0), EQ_BAND_NUM=2 ES8156_ERROR_FAILED(this->write_byte(ES8156_REG19_EQ_CONTROL1, 0x20)); + // REG0D P2S CONTROL: Parallel-to-serial converter settings ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0D_P2S_CONTROL, 0x14)); + + // REG09 MISC CONTROL 2: Default settings ES8156_ERROR_FAILED(this->write_byte(ES8156_REG09_MISC_CONTROL2, 0x00)); + + // REG18 MISC CONTROL 3: Stereo channel routing, no inversion + // Bits 5:4 CHN_CROSS: 0=L→L/R→R, 1=L to both, 2=R to both, 3=swap L/R + // Bits 3:2: LCH_INV/RCH_INV channel inversion ES8156_ERROR_FAILED(this->write_byte(ES8156_REG18_MISC_CONTROL3, 0x00)); + + // REG08 CLOCK OFF: Enable all internal clocks (0x3F = all clock gates open) ES8156_ERROR_FAILED(this->write_byte(ES8156_REG08_CLOCK_ON_OFF, 0x3F)); + + // REG00 RESET CONTROL: Reset sequence + // First: RST_DIG=1 (assert digital reset) ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x02)); + // Then: CSM_ON=1 (enable chip state machine), RST_DIG=1 ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x03)); + + // REG25 ANALOG SYSTEM: Power up analog blocks + // VMIDSEL=2 (normal VMID operation), PDN_ANA=0, ENREFR=0, ENHPCOM=0 + // PDN_DACVREFGEN=0, PDN_VREFBUF=0, PDN_DAC=0 (all enabled) ES8156_ERROR_FAILED(this->write_byte(ES8156_REG25_ANALOG_SYS5, 0x20)); }