From ba36bf6c0a911c91f43ec5dea635c1cf4824e09e Mon Sep 17 00:00:00 2001 From: Silicon Signals Date: Thu, 5 Jun 2025 20:08:48 +0530 Subject: [PATCH] audio: codec: Add driver for MAX98091 codec This patch adds a minimal driver for the MAX98091 audio codec. Currently, playback functionality is supported. Co-developed-by: Rutvij Trivedi Signed-off-by: Rutvij Trivedi Co-developed-by: Tarang Raval Signed-off-by: Tarang Raval Signed-off-by: Silicon Signals --- drivers/audio/CMakeLists.txt | 1 + drivers/audio/Kconfig | 1 + drivers/audio/Kconfig.max98091 | 10 + drivers/audio/max98091.c | 326 +++++++++++++++++++++++++ drivers/audio/max98091.h | 213 ++++++++++++++++ dts/bindings/audio/maxim,max98091.yaml | 16 ++ 6 files changed, 567 insertions(+) create mode 100644 drivers/audio/Kconfig.max98091 create mode 100644 drivers/audio/max98091.c create mode 100644 drivers/audio/max98091.h create mode 100644 dts/bindings/audio/maxim,max98091.yaml diff --git a/drivers/audio/CMakeLists.txt b/drivers/audio/CMakeLists.txt index d25e0bd4175..65fb724f1e5 100644 --- a/drivers/audio/CMakeLists.txt +++ b/drivers/audio/CMakeLists.txt @@ -14,3 +14,4 @@ zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_WM8904 wm8904.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_WM8962 wm8962.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_CS43L22 cs43l22.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_PCM1681 pcm1681.c) +zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_MAX98091 max98091.c) diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index f0838743b56..68772dcb81d 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -36,6 +36,7 @@ module-str = audio codec source "subsys/logging/Kconfig.template.log_config" source "drivers/audio/Kconfig.cs43l22" +source "drivers/audio/Kconfig.max98091" source "drivers/audio/Kconfig.pcm1681" source "drivers/audio/Kconfig.tas6422dac" source "drivers/audio/Kconfig.tlv320aic3110" diff --git a/drivers/audio/Kconfig.max98091 b/drivers/audio/Kconfig.max98091 new file mode 100644 index 00000000000..3cfec00320f --- /dev/null +++ b/drivers/audio/Kconfig.max98091 @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Silicon Signals Pvt. Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config AUDIO_CODEC_MAX98091 + bool "Maxim MAX98091 codec support" + default y + select I2C + depends on DT_HAS_MAXIM_MAX98091_ENABLED + help + Enable support for the MAX98091 I2S codec via I2C. diff --git a/drivers/audio/max98091.c b/drivers/audio/max98091.c new file mode 100644 index 00000000000..fcf6e1247e0 --- /dev/null +++ b/drivers/audio/max98091.c @@ -0,0 +1,326 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Silicon Signals Pvt. Ltd. + * Author: Rutvij Trivedi + * Author: Tarang Raval + */ + +#include +#include +#include +#include +#include "max98091.h" + +LOG_MODULE_REGISTER(maxim_max98091); + +#define DT_DRV_COMPAT maxim_max98091 + +struct max98091_config { + struct i2c_dt_spec i2c; + uint32_t mclk_freq; +}; + +static void max98091_write_reg(const struct device *dev, uint8_t reg, uint8_t val) +{ + const struct max98091_config *const dev_cfg = dev->config; + + i2c_reg_write_byte_dt(&dev_cfg->i2c, reg, val); +} + +static void max98091_read_reg(const struct device *dev, uint8_t reg, uint8_t *val) +{ + const struct max98091_config *const dev_cfg = dev->config; + + i2c_reg_read_byte_dt(&dev_cfg->i2c, reg, val); +} + +static void max98091_update_reg(const struct device *dev, uint8_t reg, uint8_t mask, uint8_t val) +{ + const struct max98091_config *const dev_cfg = dev->config; + + i2c_reg_update_byte_dt(&dev_cfg->i2c, reg, mask, val); +} + +static void max98091_soft_reset(const struct device *dev) +{ + max98091_write_reg(dev, M98091_REG_SOFTWARE_RESET, 0x01); + k_msleep(20); +} + +/* Configuration Functions */ +static int max98091_protocol_config(const struct device *dev, audio_dai_type_t dai_type) +{ + uint8_t fmt_reg = 0; + + switch (dai_type) { + case AUDIO_DAI_TYPE_I2S: + fmt_reg |= M98091_I2S_S_MASK; + break; + case AUDIO_DAI_TYPE_LEFT_JUSTIFIED: + fmt_reg |= M98091_LJ_S_MASK; + break; + case AUDIO_DAI_TYPE_RIGHT_JUSTIFIED: + fmt_reg |= M98091_RJ_S_MASK; + break; + default: + LOG_ERR("Unsupported DAI type: %d", dai_type); + return -EINVAL; + } + max98091_write_reg(dev, M98091_REG_DAI_INTERFACE, fmt_reg); + LOG_DBG("Protocol configured: 0x%02x", fmt_reg); + return 0; +} + +static int max98091_audio_fmt_config(const struct device *dev, audio_dai_cfg_t *cfg) +{ + uint8_t sample_rate; + uint8_t channels; + uint8_t word_size; + + switch (cfg->i2s.frame_clk_freq) { + case 8000: + sample_rate = M98091_SR_8K_MASK; + break; + case 16000: + sample_rate = M98091_SR_16K_MASK; + break; + case 32000: + sample_rate = M98091_SR_32K_MASK; + break; + case 44100: + sample_rate = M98091_SR_44K1_MASK; + break; + case 48000: + sample_rate = M98091_SR_48K_MASK; + break; + case 96000: + sample_rate = M98091_SR_96K_MASK; + break; + default: + LOG_ERR("Unsupported sample rate: %d", cfg->i2s.frame_clk_freq); + return -EINVAL; + } + + max98091_write_reg(dev, M98091_REG_QUICK_SAMPLE_RATE, sample_rate); + + switch (cfg->i2s.channels) { + case 1: /* Mono */ + channels = 1; + break; + case 2: /* Stereo */ + channels = 0; + break; + default: + LOG_ERR("Unsupported channels: %d", cfg->i2s.channels); + return -EINVAL; + } + max98091_update_reg(dev, M98091_REG_IO_CONFIGURATION, M98091_DMONO_MASK, channels); + + switch (cfg->i2s.word_size) { + case 16: + word_size = M98091_16B_WS; + break; + default: + LOG_ERR("Word size %d bits not supported; falling back to 16 bits", + cfg->i2s.word_size); + word_size = M98091_16B_WS; + break; + } + max98091_update_reg(dev, M98091_REG_INTERFACE_FORMAT, M98091_WS_MASK, word_size); + + return 0; +} + +static void max98091_set_system_clock(const struct device *dev, uint32_t mclk_freq) +{ + uint8_t psclk; + + if (mclk_freq >= 10000000 && mclk_freq <= 20000000) { + psclk = M98091_PSCLK_DIV1; + } else if (mclk_freq > 20000000 && mclk_freq <= 40000000) { + psclk = M98091_PSCLK_DIV2; + } else if (mclk_freq > 40000000 && mclk_freq <= 60000000) { + psclk = M98091_PSCLK_DIV4; + } else { + LOG_ERR("Invalid MCLK frequency: %u", mclk_freq); + return; + } + max98091_write_reg(dev, M98091_REG_SYSTEM_CLOCK, psclk); + LOG_DBG("System clock set: PSCLK=0x%02x", psclk); + + max98091_update_reg(dev, M98091_REG_MASTER_MODE, M98091_MAS_MASK, 0); +} + +static int max98091_set_volume_or_mute(const struct device *dev, audio_channel_t channel, int value, + bool is_volume) +{ + uint8_t hp_mask = is_volume ? M98091_HPVOLL_MASK : M98091_HPLM_MASK; + uint8_t spk_mask = is_volume ? M98091_SPVOLL_MASK : M98091_SPLM_MASK; + + switch (channel) { + case AUDIO_CHANNEL_FRONT_LEFT: + max98091_update_reg(dev, M98091_REG_LEFT_SPK_VOLUME, spk_mask, value); + return 0; + + case AUDIO_CHANNEL_FRONT_RIGHT: + max98091_update_reg(dev, M98091_REG_RIGHT_SPK_VOLUME, spk_mask, value); + return 0; + + case AUDIO_CHANNEL_HEADPHONE_LEFT: + max98091_update_reg(dev, M98091_REG_LEFT_HP_VOLUME, hp_mask, value); + return 0; + + case AUDIO_CHANNEL_HEADPHONE_RIGHT: + max98091_update_reg(dev, M98091_REG_RIGHT_HP_VOLUME, hp_mask, value); + return 0; + + case AUDIO_CHANNEL_ALL: + max98091_update_reg(dev, M98091_REG_LEFT_SPK_VOLUME, spk_mask, value); + max98091_update_reg(dev, M98091_REG_RIGHT_SPK_VOLUME, spk_mask, value); + max98091_update_reg(dev, M98091_REG_LEFT_HP_VOLUME, hp_mask, value); + max98091_update_reg(dev, M98091_REG_RIGHT_HP_VOLUME, hp_mask, value); + return 0; + + default: + return -EINVAL; + } +} + +static int max98091_out_volume_config(const struct device *dev, audio_channel_t channel, int volume) +{ + return max98091_set_volume_or_mute(dev, channel, volume, true); +} + +static int max98091_out_mute_config(const struct device *dev, audio_channel_t channel, bool mute) +{ + return max98091_set_volume_or_mute(dev, channel, mute, false); +} + +/* Audio Path Configuration */ +static void max98091_configure_output(const struct device *dev) +{ + max98091_update_reg(dev, M98091_REG_IO_CONFIGURATION, M98091_SDIEN_MASK, M98091_SDIEN_MASK); + + max98091_write_reg(dev, M98091_REG_LEFT_SPK_MIXER, M98091_MIXSPL_DACL_MASK); + max98091_write_reg(dev, M98091_REG_RIGHT_SPK_MIXER, M98091_MIXSPR_DACR_MASK); + + /* select DAC only source */ + max98091_write_reg(dev, M98091_REG_HP_CONTROL, 0x00); + + /* M98091_HPREN_MASK, M98091_HPLEN_MASK, M98091_SPREN_MASK, + * M98091_SPLEN_MASK, M98091_DAREN_MASK, M98091_DALEN_MASK + */ + max98091_write_reg(dev, M98091_REG_OUTPUT_ENABLE, 0xf3); + + max98091_out_volume_config(dev, AUDIO_CHANNEL_ALL, M98091_DEFAULT_VOLUME); + max98091_out_mute_config(dev, AUDIO_CHANNEL_ALL, false); +} + +static void max98091_start_output(const struct device *dev) +{ + ARG_UNUSED(dev); +} + +static void max98091_stop_output(const struct device *dev) +{ + ARG_UNUSED(dev); +} + +static int max98091_set_property(const struct device *dev, audio_property_t property, + audio_channel_t channel, audio_property_value_t val) +{ + switch (property) { + case AUDIO_PROPERTY_OUTPUT_VOLUME: + max98091_out_volume_config(dev, channel, val.vol); + case AUDIO_PROPERTY_OUTPUT_MUTE: + max98091_out_mute_config(dev, channel, val.mute); + default: + return -EINVAL; + } +} + +static int max98091_configure(const struct device *dev, struct audio_codec_cfg *cfg) +{ + const struct max98091_config *const dev_cfg = dev->config; + + if (cfg->dai_type >= AUDIO_DAI_TYPE_INVALID) { + LOG_ERR("dai_type not supported"); + return -EINVAL; + } + + max98091_soft_reset(dev); + + if (cfg->dai_route == AUDIO_ROUTE_BYPASS) { + return 0; + } + + /* Put the audio codec into shutdown mode */ + max98091_write_reg(dev, M98091_REG_DEVICE_SHUTDOWN, 0x00); + + max98091_write_reg(dev, M98091_REG_DAC_CONTROL, 0x00); + + max98091_write_reg(dev, M98091_REG_TDM_CONTROL, 0x00); + + /* Set DLY = 1 to conform to the I2S standard. + * DLY is only effective when TDM = 0 + */ + max98091_write_reg(dev, M98091_REG_INTERFACE_FORMAT, M98091_DLY_MASK); + + /* Configure system clock */ + max98091_set_system_clock(dev, dev_cfg->mclk_freq); + + max98091_protocol_config(dev, cfg->dai_type); + max98091_audio_fmt_config(dev, &cfg->dai_cfg); + + /* Configure audio paths based on route */ + switch (cfg->dai_route) { + case AUDIO_ROUTE_PLAYBACK: + max98091_configure_output(dev); + break; + default: + LOG_DBG("Unsupported audio route selected"); + break; + } + + /* Bring the audio codec out of shutdown mode */ + max98091_write_reg(dev, M98091_REG_DEVICE_SHUTDOWN, M98091_SHDNN_MASK); + + return 0; +} + +static const struct audio_codec_api max98091_api = { + .configure = max98091_configure, + .start_output = max98091_start_output, + .stop_output = max98091_stop_output, + .set_property = max98091_set_property, +}; + +static int max98091_init(const struct device *dev) +{ + const struct max98091_config *cfg_tan = dev->config; + uint8_t device_id; + + if (!i2c_is_ready_dt(&cfg_tan->i2c)) { + LOG_ERR("I2C bus not ready"); + return -ENODEV; + } + + max98091_read_reg(dev, M98091_REG_REVISION_ID, &device_id); + if (device_id >= M98091_REVA && (device_id <= M98091_REVA + 0x0f)) { + LOG_INF("MAX98091 Device ID: 0x%02X", device_id); + return 0; + } + + LOG_ERR("Invalid MAX98091 Device ID: 0x%02X", device_id); + return -EINVAL; +} + +#define MAX98091_INIT(inst) \ + static const struct max98091_config max98091_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .mclk_freq = DT_INST_PROP(inst, mclk_frequency)}; \ + DEVICE_DT_INST_DEFINE(inst, max98091_init, NULL, NULL, &max98091_config_##inst, \ + POST_KERNEL, CONFIG_AUDIO_CODEC_INIT_PRIORITY, &max98091_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX98091_INIT) diff --git a/drivers/audio/max98091.h b/drivers/audio/max98091.h new file mode 100644 index 00000000000..cc916c1eafd --- /dev/null +++ b/drivers/audio/max98091.h @@ -0,0 +1,213 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Silicon Signals Pvt. Ltd. + * Author: Rutvij Trivedi + * Author: Tarang Raval + */ + +#ifndef ZEPHYR_INCLUDE_CODEC_MAX98091_H_ +#define ZEPHYR_INCLUDE_CODEC_MAX98091_H_ + +/* + * MAX98091 Register Definitions + */ + +#define M98091_REG_SOFTWARE_RESET 0x00 +#define M98091_REG_DEVICE_STATUS 0x01 +#define M98091_REG_JACK_STATUS 0x02 +#define M98091_REG_INTERRUPT_S 0x03 +#define M98091_REG_MASTER_CLOCK 0x04 +#define M98091_REG_QUICK_SAMPLE_RATE 0x05 +#define M98091_REG_DAI_INTERFACE 0x06 +#define M98091_REG_DAC_PATH 0x07 +#define M98091_REG_MIC_DIRECT_TO_ADC 0x08 +#define M98091_REG_LINE_TO_ADC 0x09 +#define M98091_REG_ANALOG_MIC_LOOP 0x0A +#define M98091_REG_ANALOG_LINE_LOOP 0x0B +#define M98091_REG_RESERVED 0x0C +#define M98091_REG_LINE_INPUT_CONFIG 0x0D +#define M98091_REG_LINE_INPUT_LEVEL 0x0E +#define M98091_REG_INPUT_MODE 0x0F +#define M98091_REG_MIC1_INPUT_LEVEL 0x10 +#define M98091_REG_MIC2_INPUT_LEVEL 0x11 +#define M98091_REG_MIC_BIAS_VOLTAGE 0x12 +#define M98091_REG_DIGITAL_MIC_ENABLE 0x13 +#define M98091_REG_DIGITAL_MIC_CONFIG 0x14 +#define M98091_REG_LEFT_ADC_MIXER 0x15 +#define M98091_REG_RIGHT_ADC_MIXER 0x16 +#define M98091_REG_LEFT_ADC_LEVEL 0x17 +#define M98091_REG_RIGHT_ADC_LEVEL 0x18 +#define M98091_REG_ADC_BIQUAD_LEVEL 0x19 +#define M98091_REG_ADC_SIDETONE 0x1A +#define M98091_REG_SYSTEM_CLOCK 0x1B +#define M98091_REG_CLOCK_MODE 0x1C +#define M98091_REG_CLOCK_RATIO_NI_MSB 0x1D +#define M98091_REG_CLOCK_RATIO_NI_LSB 0x1E +#define M98091_REG_CLOCK_RATIO_MI_MSB 0x1F +#define M98091_REG_CLOCK_RATIO_MI_LSB 0x20 +#define M98091_REG_MASTER_MODE 0x21 +#define M98091_REG_INTERFACE_FORMAT 0x22 +#define M98091_REG_TDM_CONTROL 0x23 +#define M98091_REG_TDM_FORMAT 0x24 +#define M98091_REG_IO_CONFIGURATION 0x25 +#define M98091_REG_FILTER_CONFIG 0x26 +#define M98091_REG_DAI_PLAYBACK_LEVEL 0x27 +#define M98091_REG_DAI_PLAYBACK_LEVEL_EQ 0x28 +#define M98091_REG_LEFT_HP_MIXER 0x29 +#define M98091_REG_RIGHT_HP_MIXER 0x2A +#define M98091_REG_HP_CONTROL 0x2B +#define M98091_REG_LEFT_HP_VOLUME 0x2C +#define M98091_REG_RIGHT_HP_VOLUME 0x2D +#define M98091_REG_LEFT_SPK_MIXER 0x2E +#define M98091_REG_RIGHT_SPK_MIXER 0x2F +#define M98091_REG_SPK_CONTROL 0x30 +#define M98091_REG_LEFT_SPK_VOLUME 0x31 +#define M98091_REG_RIGHT_SPK_VOLUME 0x32 +#define M98091_REG_DRC_TIMING 0x33 +#define M98091_REG_DRC_COMPRESSOR 0x34 +#define M98091_REG_DRC_EXPANDER 0x35 +#define M98091_REG_DRC_GAIN 0x36 +#define M98091_REG_RCV_LOUTL_MIXER 0x37 +#define M98091_REG_RCV_LOUTL_CONTROL 0x38 +#define M98091_REG_RCV_LOUTL_VOLUME 0x39 +#define M98091_REG_LOUTR_MIXER 0x3A +#define M98091_REG_LOUTR_CONTROL 0x3B +#define M98091_REG_LOUTR_VOLUME 0x3C +#define M98091_REG_JACK_DETECT 0x3D +#define M98091_REG_INPUT_ENABLE 0x3E +#define M98091_REG_OUTPUT_ENABLE 0x3F +#define M98091_REG_LEVEL_CONTROL 0x40 +#define M98091_REG_DSP_FILTER_ENABLE 0x41 +#define M98091_REG_BIAS_CONTROL 0x42 +#define M98091_REG_DAC_CONTROL 0x43 +#define M98091_REG_ADC_CONTROL 0x44 +#define M98091_REG_DEVICE_SHUTDOWN 0x45 +#define M98091_REG_EQUALIZER_BASE 0x46 +#define M98091_REG_RECORD_BIQUAD_BASE 0xAF +#define M98091_REG_DMIC3_VOLUME 0xBE +#define M98091_REG_DMIC4_VOLUME 0xBF +#define M98091_REG_DMIC34_BQ_PREATTEN 0xC0 +#define M98091_REG_RECORD_TDM_SLOT 0xC1 +#define M98091_REG_SAMPLE_RATE 0xC2 +#define M98091_REG_DMIC34_BIQUAD_BASE 0xC3 +#define M98091_REG_REVISION_ID 0xFF + +/* MAX98090 Register Bit Fields */ + +/* M98091_REG_SOFTWARE_RESET */ +#define M98091_SWRESET_MASK BIT(7) + +/* M98091_REG_QUICK_SAMPLE_RATE */ +#define M98091_SR_96K_MASK BIT(5) +#define M98091_SR_32K_MASK BIT(4) +#define M98091_SR_48K_MASK BIT(3) +#define M98091_SR_44K1_MASK BIT(2) +#define M98091_SR_16K_MASK BIT(1) +#define M98091_SR_8K_MASK BIT(0) + +/* M98091_REG_DAI_INTERFACE */ +#define M98091_RJ_M_MASK BIT(5) +#define M98091_RJ_S_MASK BIT(4) +#define M98091_LJ_M_MASK BIT(3) +#define M98091_LJ_S_MASK BIT(2) +#define M98091_I2S_M_MASK BIT(1) +#define M98091_I2S_S_MASK BIT(0) + +/* M98091_REG_SYSTEM_CLOCK */ +#define M98091_PSCLK_DISABLED (0 << 4) +#define M98091_PSCLK_DIV1 BIT(4) +#define M98091_PSCLK_DIV2 (2 << 4) +#define M98091_PSCLK_DIV4 (3 << 4) + +/* M98091_REG_MASTER_MODE */ +#define M98091_MAS_MASK BIT(7) + +/* M98091_REG_INTERFACE_FORMAT */ +#define M98091_RJ_MASK BIT(5) +#define M98091_WCI_MASK BIT(4) +#define M98091_BCI_MASK BIT(3) +#define M98091_DLY_MASK BIT(2) +#define M98091_WS_MASK (3 << 0) +#define M98091_16B_WS (0 << 0) + +/* M98091_REG_IO_CONFIGURATION */ +#define M98091_LTEN_MASK BIT(5) +#define M98091_LBEN_MASK BIT(4) +#define M98091_DMONO_MASK BIT(3) +#define M98091_HIZOFF_MASK BIT(2) +#define M98091_SDOEN_MASK BIT(1) +#define M98091_SDIEN_MASK BIT(0) + +/* M98091_REG_LEFT_HP_MIXER */ +#define M98091_MIXHPL_MIC2_MASK BIT(5) +#define M98091_MIXHPL_MIC1_MASK BIT(4) +#define M98091_MIXHPL_LINEB_MASK BIT(3) +#define M98091_MIXHPL_LINEA_MASK BIT(2) +#define M98091_MIXHPL_DACR_MASK BIT(1) +#define M98091_MIXHPL_DACL_MASK BIT(0) +#define M98091_MIXHPL_MASK (63 << 0) + +/* M98091_REG_RIGHT_HP_MIXER */ +#define M98091_MIXHPR_MIC2_MASK BIT(5) +#define M98091_MIXHPR_MIC1_MASK BIT(4) +#define M98091_MIXHPR_LINEB_MASK BIT(3) +#define M98091_MIXHPR_LINEA_MASK BIT(2) +#define M98091_MIXHPR_DACR_MASK BIT(1) +#define M98091_MIXHPR_DACL_MASK BIT(0) +#define M98091_MIXHPR_MASK (63 << 0) + +/* M98091_REG_HP_CONTROL */ +#define M98091_MIXHPRSEL_MASK BIT(5) +#define M98091_MIXHPLSEL_MASK BIT(4) +#define M98091_MIXHPRG_MASK (3 << 2) +#define M98091_MIXHPLG_MASK (3 << 0) + +/* M98091_REG_LEFT_HP_VOLUME */ +#define M98091_HPLM_MASK BIT(7) +#define M98091_HPVOLL_MASK (31 << 0) + +/* M98091_REG_LEFT_SPK_MIXER */ +#define M98091_MIXSPL_MIC2_MASK BIT(5) +#define M98091_MIXSPL_MIC1_MASK BIT(4) +#define M98091_MIXSPL_LINEB_MASK BIT(3) +#define M98091_MIXSPL_LINEA_MASK BIT(2) +#define M98091_MIXSPL_DACR_MASK BIT(1) +#define M98091_MIXSPL_DACL_MASK BIT(0) +#define M98091_MIXSPL_MASK (63 << 0) + +/* M98091_REG_RIGHT_SPK_MIXER */ +#define M98091_SPK_SLAVE_MASK BIT(6) +#define M98091_MIXSPR_MIC2_MASK BIT(5) +#define M98091_MIXSPR_MIC1_MASK BIT(4) +#define M98091_MIXSPR_LINEB_MASK BIT(3) +#define M98091_MIXSPR_LINEA_MASK BIT(2) +#define M98091_MIXSPR_DACR_MASK BIT(1) +#define M98091_MIXSPR_DACL_MASK BIT(0) +#define M98091_MIXSPR_MASK (63 << 0) + +/* M98091_REG_SPK_CONTROL */ +#define M98091_MIXSPRG_MASK (3 << 2) +#define M98091_MIXSPLG_MASK (3 << 0) + +/* M98091_REG_LEFT_SPK_VOLUME */ +#define M98091_SPLM_MASK BIT(7) +#define M98091_SPVOLL_MASK (63 << 0) + +/* M98091_REG_OUTPUT_ENABLE */ +#define M98091_HPREN_MASK BIT(7) +#define M98091_HPLEN_MASK BIT(6) +#define M98091_SPREN_MASK BIT(5) +#define M98091_SPLEN_MASK BIT(4) +#define M98091_RCVLEN_MASK BIT(3) +#define M98091_RCVREN_MASK BIT(2) +#define M98091_DAREN_MASK BIT(1) +#define M98091_DALEN_MASK BIT(0) + +/* M98091_REG_DEVICE_SHUTDOWN */ +#define M98091_SHDNN_MASK BIT(7) + +#define M98091_DEFAULT_VOLUME 0x2A +#define M98091_REVA 0x50 + +#endif diff --git a/dts/bindings/audio/maxim,max98091.yaml b/dts/bindings/audio/maxim,max98091.yaml new file mode 100644 index 00000000000..95d9374bf7e --- /dev/null +++ b/dts/bindings/audio/maxim,max98091.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Silicon Signals Pvt. Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: MAX98091 I2S Audio Codec + +compatible: "maxim,max98091" + +include: [i2c-device.yaml] + +properties: + reg: + required: true + mclk-frequency: + type: int + required: true + description: External MCLK frequency in Hz