diff --git a/CODEOWNERS b/CODEOWNERS index 56e20133ef..e2c674cfd3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -133,6 +133,7 @@ esphome/components/ens160_i2c/* @latonita esphome/components/ens160_spi/* @latonita esphome/components/ens210/* @itn3rd77 esphome/components/es7210/* @kahrendt +esphome/components/es8156/* @kbx81 esphome/components/es8311/* @kahrendt @kroimon esphome/components/esp32/* @esphome/core esphome/components/esp32_ble/* @Rapsssito @jesserockz diff --git a/esphome/components/es8156/__init__.py b/esphome/components/es8156/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/es8156/audio_dac.py b/esphome/components/es8156/audio_dac.py new file mode 100644 index 0000000000..b9d8eae6b0 --- /dev/null +++ b/esphome/components/es8156/audio_dac.py @@ -0,0 +1,27 @@ +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 + +CODEOWNERS = ["@kbx81"] +DEPENDENCIES = ["i2c"] + +es8156_ns = cg.esphome_ns.namespace("es8156") +ES8156 = es8156_ns.class_("ES8156", AudioDac, cg.Component, i2c.I2CDevice) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ES8156), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(i2c.i2c_device_schema(0x08)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/esphome/components/es8156/es8156.cpp b/esphome/components/es8156/es8156.cpp new file mode 100644 index 0000000000..62d35aa2d2 --- /dev/null +++ b/esphome/components/es8156/es8156.cpp @@ -0,0 +1,87 @@ +#include "es8156.h" +#include "es8156_const.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include + +namespace esphome { +namespace es8156 { + +static const char *const TAG = "es8156"; + +// Mark the component as failed; use only in setup +#define ES8156_ERROR_FAILED(func) \ + if (!(func)) { \ + this->mark_failed(); \ + return; \ + } + +void ES8156::setup() { + ESP_LOGCONFIG(TAG, "Setting up ES8156..."); + + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG02_SCLK_MODE, 0x04)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG20_ANALOG_SYS1, 0x2A)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG21_ANALOG_SYS2, 0x3C)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG22_ANALOG_SYS3, 0x00)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG24_ANALOG_LP, 0x07)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG23_ANALOG_SYS4, 0x00)); + + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0A_TIME_CONTROL1, 0x01)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0B_TIME_CONTROL2, 0x01)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG11_DAC_SDP, 0x00)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG19_EQ_CONTROL1, 0x20)); + + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG0D_P2S_CONTROL, 0x14)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG09_MISC_CONTROL2, 0x00)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG18_MISC_CONTROL3, 0x00)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG08_CLOCK_ON_OFF, 0x3F)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x02)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG00_RESET, 0x03)); + ES8156_ERROR_FAILED(this->write_byte(ES8156_REG25_ANALOG_SYS5, 0x20)); +} + +void ES8156::dump_config() { + ESP_LOGCONFIG(TAG, "ES8156 Audio Codec:"); + + if (this->is_failed()) { + ESP_LOGCONFIG(TAG, " Failed to initialize"); + return; + } +} + +bool ES8156::set_volume(float volume) { + volume = clamp(volume, 0.0f, 1.0f); + uint8_t reg = remap(volume, 0.0f, 1.0f, 0, 255); + ESP_LOGV(TAG, "Setting ES8156_REG14_VOLUME_CONTROL to %u (volume: %f)", reg, volume); + return this->write_byte(ES8156_REG14_VOLUME_CONTROL, reg); +} + +float ES8156::volume() { + uint8_t reg; + this->read_byte(ES8156_REG14_VOLUME_CONTROL, ®); + return remap(reg, 0, 255, 0.0f, 1.0f); +} + +bool ES8156::set_mute_state_(bool mute_state) { + uint8_t reg13; + + this->is_muted_ = mute_state; + + if (!this->read_byte(ES8156_REG13_DAC_MUTE, ®13)) { + return false; + } + + ESP_LOGV(TAG, "Read ES8156_REG13_DAC_MUTE: %u", reg13); + + if (mute_state) { + reg13 |= BIT(1) | BIT(2); + } else { + reg13 &= ~(BIT(1) | BIT(2)); + } + + ESP_LOGV(TAG, "Setting ES8156_REG13_DAC_MUTE to %u (muted: %s)", reg13, YESNO(mute_state)); + return this->write_byte(ES8156_REG13_DAC_MUTE, reg13); +} + +} // namespace es8156 +} // namespace esphome diff --git a/esphome/components/es8156/es8156.h b/esphome/components/es8156/es8156.h new file mode 100644 index 0000000000..e973599a7a --- /dev/null +++ b/esphome/components/es8156/es8156.h @@ -0,0 +1,51 @@ +#pragma once + +#include "esphome/components/audio_dac/audio_dac.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace es8156 { + +class ES8156 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice { + public: + ///////////////////////// + // Component overrides // + ///////////////////////// + + void setup() override; + float get_setup_priority() const override { return setup_priority::DATA; } + void dump_config() override; + + //////////////////////// + // AudioDac overrides // + //////////////////////// + + /// @brief Writes the volume out to the DAC + /// @param volume floating point between 0.0 and 1.0 + /// @return True if successful and false otherwise + bool set_volume(float volume) override; + + /// @brief Gets the current volume out from the DAC + /// @return floating point between 0.0 and 1.0 + float volume() override; + + /// @brief Disables mute for audio out + /// @return True if successful and false otherwise + bool set_mute_off() override { return this->set_mute_state_(false); } + + /// @brief Enables mute for audio out + /// @return True if successful and false otherwise + bool set_mute_on() override { return this->set_mute_state_(true); } + + bool is_muted() override { return this->is_muted_; } + + protected: + /// @brief Mutes or unmutes the DAC audio out + /// @param mute_state True to mute, false to unmute + /// @return True if successful and false otherwise + bool set_mute_state_(bool mute_state); +}; + +} // namespace es8156 +} // namespace esphome diff --git a/esphome/components/es8156/es8156_const.h b/esphome/components/es8156/es8156_const.h new file mode 100644 index 0000000000..0bc8f89dd4 --- /dev/null +++ b/esphome/components/es8156/es8156_const.h @@ -0,0 +1,68 @@ +#pragma once + +#include "es8156.h" + +namespace esphome { +namespace es8156 { + +/* ES8156 register addresses */ +/* + * RESET Control + */ +static const uint8_t ES8156_REG00_RESET = 0x00; +/* + * Clock Managerment + */ +static const uint8_t ES8156_REG01_MAINCLOCK_CTL = 0x01; +static const uint8_t ES8156_REG02_SCLK_MODE = 0x02; +static const uint8_t ES8156_REG03_LRCLK_DIV_H = 0x03; +static const uint8_t ES8156_REG04_LRCLK_DIV_L = 0x04; +static const uint8_t ES8156_REG05_SCLK_DIV = 0x05; +static const uint8_t ES8156_REG06_NFS_CONFIG = 0x06; +static const uint8_t ES8156_REG07_MISC_CONTROL1 = 0x07; +static const uint8_t ES8156_REG08_CLOCK_ON_OFF = 0x08; +static const uint8_t ES8156_REG09_MISC_CONTROL2 = 0x09; +static const uint8_t ES8156_REG0A_TIME_CONTROL1 = 0x0a; +static const uint8_t ES8156_REG0B_TIME_CONTROL2 = 0x0b; +/* + * System Control + */ +static const uint8_t ES8156_REG0C_CHIP_STATUS = 0x0c; +static const uint8_t ES8156_REG0D_P2S_CONTROL = 0x0d; +static const uint8_t ES8156_REG10_DAC_OSR_COUNTER = 0x10; +/* + * SDP Control + */ +static const uint8_t ES8156_REG11_DAC_SDP = 0x11; +static const uint8_t ES8156_REG12_AUTOMUTE_SET = 0x12; +static const uint8_t ES8156_REG13_DAC_MUTE = 0x13; +static const uint8_t ES8156_REG14_VOLUME_CONTROL = 0x14; + +/* + * ALC Control + */ +static const uint8_t ES8156_REG15_ALC_CONFIG1 = 0x15; +static const uint8_t ES8156_REG16_ALC_CONFIG2 = 0x16; +static const uint8_t ES8156_REG17_ALC_CONFIG3 = 0x17; +static const uint8_t ES8156_REG18_MISC_CONTROL3 = 0x18; +static const uint8_t ES8156_REG19_EQ_CONTROL1 = 0x19; +static const uint8_t ES8156_REG1A_EQ_CONTROL2 = 0x1a; +/* + * Analog System Control + */ +static const uint8_t ES8156_REG20_ANALOG_SYS1 = 0x20; +static const uint8_t ES8156_REG21_ANALOG_SYS2 = 0x21; +static const uint8_t ES8156_REG22_ANALOG_SYS3 = 0x22; +static const uint8_t ES8156_REG23_ANALOG_SYS4 = 0x23; +static const uint8_t ES8156_REG24_ANALOG_LP = 0x24; +static const uint8_t ES8156_REG25_ANALOG_SYS5 = 0x25; +/* + * Chip Information + */ +static const uint8_t ES8156_REGFC_I2C_PAGESEL = 0xFC; +static const uint8_t ES8156_REGFD_CHIPID1 = 0xFD; +static const uint8_t ES8156_REGFE_CHIPID0 = 0xFE; +static const uint8_t ES8156_REGFF_CHIP_VERSION = 0xFF; + +} // namespace es8156 +} // namespace esphome diff --git a/tests/components/es8156/common.yaml b/tests/components/es8156/common.yaml new file mode 100644 index 0000000000..addaa0b70a --- /dev/null +++ b/tests/components/es8156/common.yaml @@ -0,0 +1,15 @@ +esphome: + on_boot: + then: + - audio_dac.mute_off: + - audio_dac.mute_on: + - audio_dac.set_volume: + volume: 50% + +i2c: + - id: i2c_es8156 + scl: ${scl_pin} + sda: ${sda_pin} + +audio_dac: + - platform: es8156 diff --git a/tests/components/es8156/test.esp32-ard.yaml b/tests/components/es8156/test.esp32-ard.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/es8156/test.esp32-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/es8156/test.esp32-c3-ard.yaml b/tests/components/es8156/test.esp32-c3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8156/test.esp32-c3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/es8156/test.esp32-c3-idf.yaml b/tests/components/es8156/test.esp32-c3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8156/test.esp32-c3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/es8156/test.esp32-idf.yaml b/tests/components/es8156/test.esp32-idf.yaml new file mode 100644 index 0000000000..63c3bd6afd --- /dev/null +++ b/tests/components/es8156/test.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO16 + sda_pin: GPIO17 + +<<: !include common.yaml diff --git a/tests/components/es8156/test.esp8266-ard.yaml b/tests/components/es8156/test.esp8266-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/es8156/test.esp8266-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml