From 2ba026e3f3585b3c1cd1330d321816b73fbe5cf2 Mon Sep 17 00:00:00 2001 From: Benjamin Lemouzy Date: Fri, 23 Jun 2023 14:36:47 +0200 Subject: [PATCH] drivers: audio: tas6422dac: add driver Add Texas Instruments TAS6422 DAC driver. Signed-off-by: Benjamin Lemouzy --- drivers/audio/CMakeLists.txt | 1 + drivers/audio/Kconfig | 1 + drivers/audio/Kconfig.tas6422dac | 11 + drivers/audio/tas6422dac.c | 379 ++++++++++++++++++++++++++ drivers/audio/tas6422dac.h | 262 ++++++++++++++++++ dts/bindings/audio/ti,tas6422dac.yaml | 12 + 6 files changed, 666 insertions(+) create mode 100644 drivers/audio/Kconfig.tas6422dac create mode 100644 drivers/audio/tas6422dac.c create mode 100644 drivers/audio/tas6422dac.h create mode 100644 dts/bindings/audio/ti,tas6422dac.yaml diff --git a/drivers/audio/CMakeLists.txt b/drivers/audio/CMakeLists.txt index 73cda8192acbd2..b1802f9cf26092 100644 --- a/drivers/audio/CMakeLists.txt +++ b/drivers/audio/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library_sources_ifdef(CONFIG_AUDIO_TLV320DAC tlv320dac310x.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_MPXXDTYY mpxxdtyy.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_MPXXDTYY mpxxdtyy-i2s.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_NRFX_PDM dmic_nrfx_pdm.c) +zephyr_library_sources_ifdef(CONFIG_AUDIO_TAS6422DAC tas6422dac.c) diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index 2eb98256aac049..a45e003f80a49e 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -29,6 +29,7 @@ module = AUDIO_CODEC module-str = audio codec source "subsys/logging/Kconfig.template.log_config" +source "drivers/audio/Kconfig.tas6422dac" source "drivers/audio/Kconfig.tlv320dac" endif # AUDIO_CODEC diff --git a/drivers/audio/Kconfig.tas6422dac b/drivers/audio/Kconfig.tas6422dac new file mode 100644 index 00000000000000..1977e7b6331f9a --- /dev/null +++ b/drivers/audio/Kconfig.tas6422dac @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Centralp +# SPDX-License-Identifier: Apache-2.0 + +config AUDIO_TAS6422DAC + bool "TAS6422 audio amplifier support" + default y + depends on DT_HAS_TI_TAS6422DAC_ENABLED + select I2C + depends on GPIO + help + Enable TAS6422 support on the selected board diff --git a/drivers/audio/tas6422dac.c b/drivers/audio/tas6422dac.c new file mode 100644 index 00000000000000..91c36de289788f --- /dev/null +++ b/drivers/audio/tas6422dac.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2023 Centralp + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_tas6422dac + +#include +#include +#include +#include + +#include "tas6422dac.h" + +#define LOG_LEVEL CONFIG_AUDIO_CODEC_LOG_LEVEL +#include +LOG_MODULE_REGISTER(tas6422dac); + +#define TAS6422DAC_MUTE_GPIO_SUPPORT DT_ANY_INST_HAS_PROP_STATUS_OKAY(mute_gpios) + +#define CODEC_OUTPUT_VOLUME_MAX (24 * 2) +#define CODEC_OUTPUT_VOLUME_MIN (-100 * 2) + +struct codec_driver_config { + struct i2c_dt_spec bus; +#if TAS6422DAC_MUTE_GPIO_SUPPORT + struct gpio_dt_spec mute_gpio; +#endif /* TAS6422DAC_MUTE_GPIO_SUPPORT */ +}; + +struct codec_driver_data { +}; + +enum tas6422dac_channel_t { + TAS6422DAC_CHANNEL_1, + TAS6422DAC_CHANNEL_2, + TAS6422DAC_CHANNEL_ALL, + TAS6422DAC_CHANNEL_UNKNOWN, +}; + +static enum tas6422dac_channel_t audio_to_tas6422dac_channel[] = { + [AUDIO_CHANNEL_FRONT_LEFT] = TAS6422DAC_CHANNEL_1, + [AUDIO_CHANNEL_FRONT_RIGHT] = TAS6422DAC_CHANNEL_2, + [AUDIO_CHANNEL_LFE] = TAS6422DAC_CHANNEL_UNKNOWN, + [AUDIO_CHANNEL_FRONT_CENTER] = TAS6422DAC_CHANNEL_UNKNOWN, + [AUDIO_CHANNEL_REAR_LEFT] = TAS6422DAC_CHANNEL_1, + [AUDIO_CHANNEL_REAR_RIGHT] = TAS6422DAC_CHANNEL_2, + [AUDIO_CHANNEL_REAR_CENTER] = TAS6422DAC_CHANNEL_UNKNOWN, + [AUDIO_CHANNEL_SIDE_LEFT] = TAS6422DAC_CHANNEL_1, + [AUDIO_CHANNEL_SIDE_RIGHT] = TAS6422DAC_CHANNEL_2, + [AUDIO_CHANNEL_ALL] = TAS6422DAC_CHANNEL_ALL, +}; + +static void codec_mute_output(const struct device *dev, enum tas6422dac_channel_t channel); +static void codec_unmute_output(const struct device *dev, enum tas6422dac_channel_t channel); +static void codec_write_reg(const struct device *dev, uint8_t reg, uint8_t val); +static void codec_read_reg(const struct device *dev, uint8_t reg, uint8_t *val); +static void codec_soft_reset(const struct device *dev); +static int codec_configure_dai(const struct device *dev, audio_dai_cfg_t *cfg); +static void codec_configure_output(const struct device *dev); +static int codec_set_output_volume(const struct device *dev, enum tas6422dac_channel_t channel, + int vol); + +#if (LOG_LEVEL >= LOG_LEVEL_DEBUG) +static void codec_read_all_regs(const struct device *dev); +#define CODEC_DUMP_REGS(dev) codec_read_all_regs((dev)) +#else +#define CODEC_DUMP_REGS(dev) +#endif + +static int codec_initialize(const struct device *dev) +{ + const struct codec_driver_config *const dev_cfg = dev->config; + + if (!device_is_ready(dev_cfg->bus.bus)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + +#if TAS6422DAC_MUTE_GPIO_SUPPORT + if (!device_is_ready(dev_cfg->mute_gpio.port)) { + LOG_ERR("GPIO device not ready"); + return -ENODEV; + } +#endif /* TAS6422DAC_MUTE_GPIO_SUPPORT */ + + return 0; +} + +static int codec_configure(const struct device *dev, struct audio_codec_cfg *cfg) +{ + int ret; + + if (cfg->dai_type != AUDIO_DAI_TYPE_I2S) { + LOG_ERR("dai_type must be AUDIO_DAI_TYPE_I2S"); + return -EINVAL; + } + + codec_soft_reset(dev); + ret = codec_configure_dai(dev, &cfg->dai_cfg); + codec_configure_output(dev); + + return ret; +} + +static void codec_start_output(const struct device *dev) +{ + codec_unmute_output(dev, TAS6422DAC_CHANNEL_ALL); + + CODEC_DUMP_REGS(dev); +} + +static void codec_stop_output(const struct device *dev) +{ + codec_mute_output(dev, TAS6422DAC_CHANNEL_ALL); +} + +static void codec_mute_output(const struct device *dev, enum tas6422dac_channel_t channel) +{ + uint8_t val; + +#if TAS6422DAC_MUTE_GPIO_SUPPORT + const struct codec_driver_config *const dev_cfg = dev->config; + + gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_ACTIVE); +#endif + + codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val); + switch (channel) { + case TAS6422DAC_CHANNEL_1: + val &= ~CH_STATE_CTRL_CH1_STATE_CTRL_MASK; + val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_MUTE); + break; + case TAS6422DAC_CHANNEL_2: + val &= ~CH_STATE_CTRL_CH2_STATE_CTRL_MASK; + val |= CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_MUTE); + break; + case TAS6422DAC_CHANNEL_ALL: + val &= ~(CH_STATE_CTRL_CH1_STATE_CTRL_MASK | CH_STATE_CTRL_CH2_STATE_CTRL_MASK); + val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_MUTE) | + CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_MUTE); + break; + case TAS6422DAC_CHANNEL_UNKNOWN: + default: + LOG_ERR("Invalid codec channel %u", channel); + return; + } + codec_write_reg(dev, CH_STATE_CTRL_ADDR, val); +} + +static void codec_unmute_output(const struct device *dev, enum tas6422dac_channel_t channel) +{ + uint8_t val; + +#if TAS6422DAC_MUTE_GPIO_SUPPORT + const struct codec_driver_config *const dev_cfg = dev->config; + + gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_INACTIVE); +#endif + + codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val); + switch (channel) { + case TAS6422DAC_CHANNEL_1: + val &= ~CH_STATE_CTRL_CH1_STATE_CTRL_MASK; + val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_PLAY); + break; + case TAS6422DAC_CHANNEL_2: + val &= ~CH_STATE_CTRL_CH2_STATE_CTRL_MASK; + val |= CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_PLAY); + break; + case TAS6422DAC_CHANNEL_ALL: + val &= ~(CH_STATE_CTRL_CH1_STATE_CTRL_MASK | CH_STATE_CTRL_CH2_STATE_CTRL_MASK); + val |= CH_STATE_CTRL_CH1_STATE_CTRL(CH_STATE_CTRL_PLAY) | + CH_STATE_CTRL_CH2_STATE_CTRL(CH_STATE_CTRL_PLAY); + break; + case TAS6422DAC_CHANNEL_UNKNOWN: + default: + LOG_ERR("Invalid codec channel %u", channel); + return; + } + codec_write_reg(dev, CH_STATE_CTRL_ADDR, val); +} + +static int codec_set_property(const struct device *dev, audio_property_t property, + audio_channel_t channel, audio_property_value_t val) +{ + enum tas6422dac_channel_t codec_channel = audio_to_tas6422dac_channel[channel]; + + if (codec_channel == TAS6422DAC_CHANNEL_UNKNOWN) { + LOG_ERR("Invalid channel %u", channel); + return -EINVAL; + } + + switch (property) { + case AUDIO_PROPERTY_OUTPUT_VOLUME: + return codec_set_output_volume(dev, codec_channel, val.vol); + + case AUDIO_PROPERTY_OUTPUT_MUTE: + if (val.mute) { + codec_mute_output(dev, codec_channel); + } else { + codec_unmute_output(dev, codec_channel); + } + return 0; + + default: + break; + } + + return -EINVAL; +} + +static int codec_apply_properties(const struct device *dev) +{ + /* nothing to do because there is nothing cached */ + return 0; +} + +static void codec_write_reg(const struct device *dev, uint8_t reg, uint8_t val) +{ + const struct codec_driver_config *const dev_cfg = dev->config; + + i2c_reg_write_byte_dt(&dev_cfg->bus, reg, val); + LOG_DBG("%s WR REG:0x%02x VAL:0x%02x", dev->name, reg, val); +} + +static void codec_read_reg(const struct device *dev, uint8_t reg, uint8_t *val) +{ + const struct codec_driver_config *const dev_cfg = dev->config; + + i2c_reg_read_byte_dt(&dev_cfg->bus, reg, val); + LOG_DBG("%s RD REG:0x%02x VAL:0x%02x", dev->name, reg, *val); +} + +static void codec_soft_reset(const struct device *dev) +{ + uint8_t val; + + codec_read_reg(dev, MODE_CTRL_ADDR, &val); + val |= MODE_CTRL_RESET; + codec_write_reg(dev, MODE_CTRL_ADDR, val); +} + +static int codec_configure_dai(const struct device *dev, audio_dai_cfg_t *cfg) +{ + uint8_t val; + + codec_read_reg(dev, SAP_CTRL_ADDR, &val); + + /* I2S mode */ + val &= ~SAP_CTRL_INPUT_FORMAT_MASK; + val |= SAP_CTRL_INPUT_FORMAT(SAP_CTRL_INPUT_FORMAT_I2S); + + /* Input sampling rate */ + val &= ~SAP_CTRL_INPUT_SAMPLING_RATE_MASK; + switch (cfg->i2s.frame_clk_freq) { + case AUDIO_PCM_RATE_44P1K: + val |= SAP_CTRL_INPUT_SAMPLING_RATE(SAP_CTRL_INPUT_SAMPLING_RATE_44_1_KHZ); + break; + case AUDIO_PCM_RATE_48K: + val |= SAP_CTRL_INPUT_SAMPLING_RATE(SAP_CTRL_INPUT_SAMPLING_RATE_48_KHZ); + break; + case AUDIO_PCM_RATE_96K: + val |= SAP_CTRL_INPUT_SAMPLING_RATE(SAP_CTRL_INPUT_SAMPLING_RATE_96_KHZ); + break; + default: + LOG_ERR("Invalid sampling rate %zu", cfg->i2s.frame_clk_freq); + return -EINVAL; + } + + codec_write_reg(dev, SAP_CTRL_ADDR, val); + + return 0; +} + +static void codec_configure_output(const struct device *dev) +{ + uint8_t val; + + /* Overcurrent level = 1 */ + codec_read_reg(dev, MISC_CTRL_1_ADDR, &val); + val &= ~MISC_CTRL_1_OC_CONTROL_MASK; + codec_write_reg(dev, MISC_CTRL_1_ADDR, val); + + /* + * PWM frequency = 10 fs + * Reduce PWM frequency to prevent component overtemperature + */ + codec_read_reg(dev, MISC_CTRL_2_ADDR, &val); + val &= ~MISC_CTRL_2_PWM_FREQUENCY_MASK; + val |= MISC_CTRL_2_PWM_FREQUENCY(MISC_CTRL_2_PWM_FREQUENCY_10_FS); + codec_write_reg(dev, MISC_CTRL_2_ADDR, val); +} + +static int codec_set_output_volume(const struct device *dev, enum tas6422dac_channel_t channel, + int vol) +{ + uint8_t vol_val; + + if ((vol > CODEC_OUTPUT_VOLUME_MAX) || (vol < CODEC_OUTPUT_VOLUME_MIN)) { + LOG_ERR("Invalid volume %d.%d dB", vol >> 1, ((uint32_t)vol & 1) ? 5 : 0); + return -EINVAL; + } + + vol_val = vol + 0xcf; + switch (channel) { + case TAS6422DAC_CHANNEL_1: + codec_write_reg(dev, CH1_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val)); + break; + case TAS6422DAC_CHANNEL_2: + codec_write_reg(dev, CH2_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val)); + break; + case TAS6422DAC_CHANNEL_ALL: + codec_write_reg(dev, CH1_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val)); + codec_write_reg(dev, CH2_VOLUME_CTRL_ADDR, CH_VOLUME_CTRL_VOLUME(vol_val)); + break; + case TAS6422DAC_CHANNEL_UNKNOWN: + default: + LOG_ERR("Invalid codec channel %u", channel); + return -EINVAL; + } + + return 0; +} + +#if (LOG_LEVEL >= LOG_LEVEL_DEBUG) +static void codec_read_all_regs(const struct device *dev) +{ + uint8_t val; + + codec_read_reg(dev, MODE_CTRL_ADDR, &val); + codec_read_reg(dev, MISC_CTRL_1_ADDR, &val); + codec_read_reg(dev, MISC_CTRL_2_ADDR, &val); + codec_read_reg(dev, SAP_CTRL_ADDR, &val); + codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val); + codec_read_reg(dev, CH1_VOLUME_CTRL_ADDR, &val); + codec_read_reg(dev, CH2_VOLUME_CTRL_ADDR, &val); + codec_read_reg(dev, DC_LDG_CTRL_1_ADDR, &val); + codec_read_reg(dev, DC_LDG_CTRL_2_ADDR, &val); + codec_read_reg(dev, DC_LDG_REPORT_1_ADDR, &val); + codec_read_reg(dev, DC_LDG_REPORT_3_ADDR, &val); + codec_read_reg(dev, CH_FAULTS_ADDR, &val); + codec_read_reg(dev, GLOBAL_FAULTS_1_ADDR, &val); + codec_read_reg(dev, GLOBAL_FAULTS_2_ADDR, &val); + codec_read_reg(dev, WARNINGS_ADDR, &val); + codec_read_reg(dev, PIN_CTRL_ADDR, &val); + codec_read_reg(dev, MISC_CTRL_3_ADDR, &val); + codec_read_reg(dev, ILIMIT_STATUS_ADDR, &val); + codec_read_reg(dev, MISC_CTRL_4_ADDR, &val); + codec_read_reg(dev, MISC_CTRL_5_ADDR, &val); +} +#endif + +static const struct audio_codec_api codec_driver_api = { + .configure = codec_configure, + .start_output = codec_start_output, + .stop_output = codec_stop_output, + .set_property = codec_set_property, + .apply_properties = codec_apply_properties, +}; + +#if TAS6422DAC_MUTE_GPIO_SUPPORT +#define TAS6422DAC_MUTE_GPIO_INIT(n) .mute_gpio = GPIO_DT_SPEC_INST_GET(n, mute_gpios) +#else +#define TAS6422DAC_MUTE_GPIO_INIT(n) +#endif /* TAS6422DAC_MUTE_GPIO_SUPPORT */ + +#define TAS6422DAC_INIT(n) \ + static struct codec_driver_data codec_device_data_##n; \ + \ + static struct codec_driver_config codec_device_config_##n = { \ + .bus = I2C_DT_SPEC_INST_GET(n), TAS6422DAC_MUTE_GPIO_INIT(n)}; \ + \ + DEVICE_DT_INST_DEFINE(n, codec_initialize, NULL, &codec_device_data_##n, \ + &codec_device_config_##n, POST_KERNEL, \ + CONFIG_AUDIO_CODEC_INIT_PRIORITY, &codec_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TAS6422DAC_INIT) diff --git a/drivers/audio/tas6422dac.h b/drivers/audio/tas6422dac.h new file mode 100644 index 00000000000000..84ec0872636b08 --- /dev/null +++ b/drivers/audio/tas6422dac.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2023 Centralp + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_AUDIO_TAS6422DAC_H_ +#define ZEPHYR_DRIVERS_AUDIO_TAS6422DAC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Mode Control Register */ +#define MODE_CTRL_ADDR 0x00 +#define MODE_CTRL_RESET BIT(7) +#define MODE_CTRL_RESET_MASK BIT(7) +#define MODE_CTRL_PBTL_CH12 BIT(4) +#define MODE_CTRL_PBTL_CH12_MASK BIT(4) +#define MODE_CTRL_CH1_LO_MODE BIT(3) +#define MODE_CTRL_CH1_LO_MODE_MASK BIT(3) +#define MODE_CTRL_CH2_LO_MODE BIT(2) +#define MODE_CTRL_CH2_LO_MODE_MASK BIT(2) + +/* Miscellaneous Control 1 Register */ +#define MISC_CTRL_1_ADDR 0x01 +#define MISC_CTRL_1_HPF_BYPASS BIT(7) +#define MISC_CTRL_1_HPF_BYPASS_MASK BIT(7) +#define MISC_CTRL_1_OTW_CONTROL_MASK (BIT_MASK(2) << 5) +#define MISC_CTRL_1_OTW_CONTROL(val) (((val) << 5) & MISC_CTRL_1_OTW_CONTROL_MASK) +#define MISC_CTRL_1_OTW_CONTROL_140_DEGREE 0 +#define MISC_CTRL_1_OTW_CONTROL_130_DEGREE 1 +#define MISC_CTRL_1_OTW_CONTROL_120_DEGREE 2 +#define MISC_CTRL_1_OTW_CONTROL_110_DEGREE 3 +#define MISC_CTRL_1_OC_CONTROL BIT(4) +#define MISC_CTRL_1_OC_CONTROL_MASK BIT(4) +#define MISC_CTRL_1_VOLUME_RATE_MASK (BIT_MASK(2) << 2) +#define MISC_CTRL_1_VOLUME_RATE(val) (((val) << 2) & MISC_CTRL_1_VOLUME_RATE_MASK) +#define MISC_CTRL_1_VOLUME_RATE_1_STEP_EVERY_1_FSYNC 0 +#define MISC_CTRL_1_VOLUME_RATE_1_STEP_EVERY_2_FSYNC 1 +#define MISC_CTRL_1_VOLUME_RATE_1_STEP_EVERY_4_FSYNC 2 +#define MISC_CTRL_1_VOLUME_RATE_1_STEP_EVERY_8_FSYNC 3 +#define MISC_CTRL_1_GAIN_MASK BIT_MASK(2) +#define MISC_CTRL_1_GAIN(val) ((val) & MISC_CTRL_1_GAIN_MASK) +#define MISC_CTRL_1_GAIN_7_5_V_PEAK_OUTPUT 0 +#define MISC_CTRL_1_GAIN_15_V_PEAK_OUTPUT 1 +#define MISC_CTRL_1_GAIN_21_V_PEAK_OUTPUT 2 +#define MISC_CTRL_1_GAIN_29_V_PEAK_OUTPUT 3 + +/* Miscellaneous Control 2 Register */ +#define MISC_CTRL_2_ADDR 0x02 +#define MISC_CTRL_2_PWM_FREQUENCY_MASK (BIT_MASK(3) << 4) +#define MISC_CTRL_2_PWM_FREQUENCY(val) (((val) << 4) & MISC_CTRL_2_PWM_FREQUENCY_MASK) +#define MISC_CTRL_2_PWM_FREQUENCY_8_FS 0 +#define MISC_CTRL_2_PWM_FREQUENCY_10_FS 1 +#define MISC_CTRL_2_PWM_FREQUENCY_38_FS 5 +#define MISC_CTRL_2_PWM_FREQUENCY_44_FS 6 +#define MISC_CTRL_2_PWM_FREQUENCY_48_FS 7 +#define MISC_CTRL_2_SDM_OSR BIT(2) +#define MISC_CTRL_2_SDM_OSR_MASK BIT(2) +#define MISC_CTRL_2_OUTPUT_PHASE_MASK BIT_MASK(2) +#define MISC_CTRL_2_OUTPUT_PHASE(val) ((val) & MISC_CTRL_2_OUTPUT_PHASE_MASK) +#define MISC_CTRL_2_OUTPUT_PHASE_210_DEGREES 1 +#define MISC_CTRL_2_OUTPUT_PHASE_225_DEGREES 2 +#define MISC_CTRL_2_OUTPUT_PHASE_240_DEGREES 3 + +/* Serial Audio-Port Control Register */ +#define SAP_CTRL_ADDR 0x03 +#define SAP_CTRL_INPUT_SAMPLING_RATE_MASK (BIT_MASK(2) << 6) +#define SAP_CTRL_INPUT_SAMPLING_RATE(val) (((val) << 6) & SAP_CTRL_INPUT_SAMPLING_RATE_MASK) +#define SAP_CTRL_INPUT_SAMPLING_RATE_44_1_KHZ 0 +#define SAP_CTRL_INPUT_SAMPLING_RATE_48_KHZ 1 +#define SAP_CTRL_INPUT_SAMPLING_RATE_96_KHZ 2 +#define SAP_CTRL_TDM_SLOT_SELECT BIT(5) +#define SAP_CTRL_TDM_SLOT_SELECT_MASK BIT(5) +#define SAP_CTRL_TDM_SLOT_SIZE BIT(4) +#define SAP_CTRL_TDM_SLOT_SIZE_MASK BIT(4) +#define SAP_CTRL_TDM_SLOT_SELECT_2 BIT(3) +#define SAP_CTRL_TDM_SLOT_SELECT_2_MASK BIT(3) +#define SAP_CTRL_INPUT_FORMAT_MASK BIT_MASK(3) +#define SAP_CTRL_INPUT_FORMAT(val) ((val) & SAP_CTRL_INPUT_FORMAT_MASK) +#define SAP_CTRL_INPUT_FORMAT_24_BITS_RIGHT 0 +#define SAP_CTRL_INPUT_FORMAT_20_BITS_RIGHT 1 +#define SAP_CTRL_INPUT_FORMAT_18_BITS_RIGHT 2 +#define SAP_CTRL_INPUT_FORMAT_16_BITS_RIGHT 3 +#define SAP_CTRL_INPUT_FORMAT_I2S 4 +#define SAP_CTRL_INPUT_FORMAT_LEFT 5 +#define SAP_CTRL_INPUT_FORMAT_DSP 6 + +/* Channel State Control Register */ +#define CH_STATE_CTRL_ADDR 0x04 +#define CH_STATE_CTRL_CH1_STATE_CTRL_MASK (BIT_MASK(2) << 6) +#define CH_STATE_CTRL_CH1_STATE_CTRL(val) (((val) << 6) & CH_STATE_CTRL_CH1_STATE_CTRL_MASK) +#define CH_STATE_CTRL_CH2_STATE_CTRL_MASK (BIT_MASK(2) << 4) +#define CH_STATE_CTRL_CH2_STATE_CTRL(val) (((val) << 4) & CH_STATE_CTRL_CH2_STATE_CTRL_MASK) +#define CH_STATE_CTRL_PLAY 0 +#define CH_STATE_CTRL_HIZ 1 +#define CH_STATE_CTRL_MUTE 2 +#define CH_STATE_CTRL_DC_LOAD 3 + +/* Channel 1 and 2 Volume Control Registers */ +#define CH1_VOLUME_CTRL_ADDR 0x05 +#define CH2_VOLUME_CTRL_ADDR 0x06 +#define CH_VOLUME_CTRL_VOLUME_MASK BIT_MASK(8) +#define CH_VOLUME_CTRL_VOLUME(val) ((val) & CH_VOLUME_CTRL_VOLUME_MASK) + +/* DC Load Diagnostic Control 1 Register */ +#define DC_LDG_CTRL_1_ADDR 0x09 +#define DC_LDG_CTRL_1_ABORT BIT(7) +#define DC_LDG_CTRL_1_ABORT_MASK BIT(7) +#define DC_LDG_CTRL_1_DOUBLE_RAMP BIT(6) +#define DC_LDG_CTRL_1_DOUBLE_RAMP_MASK BIT(6) +#define DC_LDG_CTRL_1_DOUBLE_SETTLE BIT(5) +#define DC_LDG_CTRL_1_DOUBLE_SETTLE_MASK BIT(5) +#define DC_LDG_CTRL_1_LO_ENABLE BIT(1) +#define DC_LDG_CTRL_1_LO_ENABLE_MASK BIT(1) +#define DC_LDG_CTRL_1_BYPASS BIT(0) +#define DC_LDG_CTRL_1_BYPASS_MASK BIT(0) + +/* DC Load Diagnostic Control 2 Register */ +#define DC_LDG_CTRL_2_ADDR 0x0A +#define DC_LDG_CTRL_2_CH1_SL_MASK (BIT_MASK(4) << 4) +#define DC_LDG_CTRL_2_CH1_SL(val) (((val) << 4) & DC_LDG_CTRL_2_CH1_SL_MASK) +#define DC_LDG_CTRL_2_CH2_SL_MASK BIT_MASK(4) +#define DC_LDG_CTRL_2_CH2_SL(val) ((val) & DC_LDG_CTRL_2_CH2_SL_MASK) + +/* DC Load Diagnostics Report 1 */ +#define DC_LDG_REPORT_1_ADDR 0x0C +#define DC_LDG_REPORT_1_CH1_S2G BIT(7) +#define DC_LDG_REPORT_1_CH1_S2G_MASK BIT(7) +#define DC_LDG_REPORT_1_CH1_S2P BIT(6) +#define DC_LDG_REPORT_1_CH1_S2P_MASK BIT(6) +#define DC_LDG_REPORT_1_CH1_OL BIT(5) +#define DC_LDG_REPORT_1_CH1_OL_MASK BIT(5) +#define DC_LDG_REPORT_1_CH1_SL BIT(4) +#define DC_LDG_REPORT_1_CH1_SL_MASK BIT(4) +#define DC_LDG_REPORT_1_CH2_S2G BIT(3) +#define DC_LDG_REPORT_1_CH2_S2G_MASK BIT(3) +#define DC_LDG_REPORT_1_CH2_S2P BIT(2) +#define DC_LDG_REPORT_1_CH2_S2P_MASK BIT(2) +#define DC_LDG_REPORT_1_CH2_OL BIT(1) +#define DC_LDG_REPORT_1_CH2_OL_MASK BIT(1) +#define DC_LDG_REPORT_1_CH2_SL BIT(0) +#define DC_LDG_REPORT_1_CH2_SL_MASK BIT(0) + +/* DC Load Diagnostics Report 3 */ +#define DC_LDG_REPORT_3_ADDR 0x0E +#define DC_LDG_REPORT_3_CH1_LO BIT(3) +#define DC_LDG_REPORT_3_CH1_LO_MASK BIT(3) +#define DC_LDG_REPORT_3_CH2_LO BIT(2) +#define DC_LDG_REPORT_3_CH2_LO_MASK BIT(2) + +/* Channel Faults Register */ +#define CH_FAULTS_ADDR 0x10 +#define CH_FAULTS_CH1_OC BIT(7) +#define CH_FAULTS_CH1_OC_MASK BIT(7) +#define CH_FAULTS_CH2_OC BIT(6) +#define CH_FAULTS_CH2_OC_MASK BIT(6) +#define CH_FAULTS_CH1_DC BIT(3) +#define CH_FAULTS_CH1_DC_MASK BIT(3) +#define CH_FAULTS_CH2_DC BIT(2) +#define CH_FAULTS_CH2_DC_MASK BIT(2) + +/* Global Faults 1 Register */ +#define GLOBAL_FAULTS_1_ADDR 0x11 +#define GLOBAL_FAULTS_1_INVALID_CLOCK BIT(4) +#define GLOBAL_FAULTS_1_INVALID_CLOCK_MASK BIT(4) +#define GLOBAL_FAULTS_1_PVDD_OV BIT(3) +#define GLOBAL_FAULTS_1_PVDD_OV_MASK BIT(3) +#define GLOBAL_FAULTS_1_VBAT_OV BIT(2) +#define GLOBAL_FAULTS_1_VBAT_OV_MASK BIT(2) +#define GLOBAL_FAULTS_1_PVDD_UV BIT(1) +#define GLOBAL_FAULTS_1_PVDD_UV_MASK BIT(1) +#define GLOBAL_FAULTS_1_VBAT_UV BIT(0) +#define GLOBAL_FAULTS_1_VBAT_UV_MASK BIT(0) + +/* Global Faults 2 Register */ +#define GLOBAL_FAULTS_2_ADDR 0x12 +#define GLOBAL_FAULTS_2_OTSD BIT(4) +#define GLOBAL_FAULTS_2_OTSD_MASK BIT(4) +#define GLOBAL_FAULTS_2_CH1_OTSD BIT(3) +#define GLOBAL_FAULTS_2_CH1_OTSD_MASK BIT(3) +#define GLOBAL_FAULTS_2_CH2_OTSD BIT(2) +#define GLOBAL_FAULTS_2_CH2_OTSD_MASK BIT(2) + +/* Warnings Register */ +#define WARNINGS_ADDR 0x13 +#define WARNINGS_VDD_POR BIT(5) +#define WARNINGS_VDD_POR_MASK BIT(5) +#define WARNINGS_OTW BIT(4) +#define WARNINGS_OTW_MASK BIT(4) +#define WARNINGS_OTW_CH1 BIT(3) +#define WARNINGS_OTW_CH1_MASK BIT(3) +#define WARNINGS_OTW_CH2 BIT(2) +#define WARNINGS_OTW_CH2_MASK BIT(2) + +/* Pin Control Register */ +#define PIN_CTRL_ADDR 0x14 +#define PIN_CTRL_MASK_OC BIT(7) +#define PIN_CTRL_MASK_OC_MASK BIT(7) +#define PIN_CTRL_MASK_OTSD BIT(6) +#define PIN_CTRL_MASK_OTSD_MASK BIT(6) +#define PIN_CTRL_MASK_UV BIT(5) +#define PIN_CTRL_MASK_UV_MASK BIT(5) +#define PIN_CTRL_MASK_OV BIT(4) +#define PIN_CTRL_MASK_OV_MASK BIT(4) +#define PIN_CTRL_MASK_DC BIT(3) +#define PIN_CTRL_MASK_DC_MASK BIT(3) +#define PIN_CTRL_MASK_ILIMIT BIT(2) +#define PIN_CTRL_MASK_ILIMIT_MASK BIT(2) +#define PIN_CTRL_MASK_CLIP BIT(1) +#define PIN_CTRL_MASK_CLIP_MASK BIT(1) +#define PIN_CTRL_MASK_OTW BIT(0) +#define PIN_CTRL_MASK_OTW_MASK BIT(0) + +/* Miscellaneous Control 3 Register */ +#define MISC_CTRL_3_ADDR 0x21 +#define MISC_CTRL_3_CLEAR_FAULT BIT(7) +#define MISC_CTRL_3_CLEAR_FAULT_MASK BIT(7) +#define MISC_CTRL_3_PBTL_CH_SEL BIT(6) +#define MISC_CTRL_3_PBTL_CH_SEL_MASK BIT(6) +#define MISC_CTRL_3_MASK_ILIMIT BIT(5) +#define MISC_CTRL_3_MASK_ILIMIT_MASK BIT(5) +#define MISC_CTRL_3_OTSD_AUTO_RECOVERY BIT(3) +#define MISC_CTRL_3_OTSD_AUTO_RECOVERY_MASK BIT(3) + +/* ILIMIT Status Register */ +#define ILIMIT_STATUS_ADDR 0x25 +#define ILIMIT_STATUS_CH2_ILIMIT_WARN BIT(1) +#define ILIMIT_STATUS_CH2_ILIMIT_WARN_MASK BIT(1) +#define ILIMIT_STATUS_CH1_ILIMIT_WARN BIT(0) +#define ILIMIT_STATUS_CH1_ILIMIT_WARN_MASK BIT(0) + +/* Miscellaneous Control 4 Register */ +#define MISC_CTRL_4_ADDR 0x26 +#define MISC_CTRL_4_HPF_CORNER_MASK BIT_MASK(3) +#define MISC_CTRL_4_HPF_CORNER(val) ((val) & MISC_CTRL_4_HPF_CORNER_MASK) +#define MISC_CTRL_4_HPF_CORNER_3_7_HZ 0 +#define MISC_CTRL_4_HPF_CORNER_7_4_HZ 1 +#define MISC_CTRL_4_HPF_CORNER_15_HZ 2 +#define MISC_CTRL_4_HPF_CORNER_30_HZ 3 +#define MISC_CTRL_4_HPF_CORNER_59_HZ 4 +#define MISC_CTRL_4_HPF_CORNER_118_HZ 5 +#define MISC_CTRL_4_HPF_CORNER_235_HZ 6 +#define MISC_CTRL_4_HPF_CORNER_463_HZ 7 + +/* Miscellaneous Control 5 Register */ +#define MISC_CTRL_5_ADDR 0x28 +#define MISC_CTRL_5_SS_BW_SEL BIT(7) +#define MISC_CTRL_5_SS_BW_SEL_MASK BIT(7) +#define MISC_CTRL_5_SS_DIV2 BIT(6) +#define MISC_CTRL_5_SS_DIV2_MASK BIT(6) +#define MISC_CTRL_5_PHASE_SEL_MSB BIT(5) +#define MISC_CTRL_5_PHASE_SEL_MSB_MASK BIT(5) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_AUDIO_TAS6422DAC_H_ */ diff --git a/dts/bindings/audio/ti,tas6422dac.yaml b/dts/bindings/audio/ti,tas6422dac.yaml new file mode 100644 index 00000000000000..5889d76f82726d --- /dev/null +++ b/dts/bindings/audio/ti,tas6422dac.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Centralp +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instruments TAS6422 Audio Amplifier + +compatible: "ti,tas6422dac" + +include: i2c-device.yaml + +properties: + mute-gpios: + type: phandle-array