blob: 1ea976bf7d9da8371aa999f7dbf33b52884645a6 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_MEDIA_AUDIO_DRIVERS_CODECS_ALC5663_ALC5663_REGISTERS_H_
#define SRC_MEDIA_AUDIO_DRIVERS_CODECS_ALC5663_ALC5663_REGISTERS_H_
#include <zircon/types.h>
#include <hwreg/bitfields.h>
//
// Register definitions taken from:
//
// ALC5663 (ALC5663-CG)
// 32bits Hi-Fi Digital Audio Headphone Amplifier
// Revision 0.9
// 6 April 2017
// Realtek Semiconductor Corp.
//
// Some register definitions are marked with "(??)". These are definitions that are
// not referenced in the datasheet above, but are nevertheless required for audio
// output to work. The values were derived by comparing the I2C register values of
// an ALC5663 codec playing audio on a working system against the values specified
// by the ALC5663 datasheets. The names and field locations of such registers are
// guesses based on inspecting datasheets of other Realtek codecs, and empirically
// trying different values. Fields marked with "(??)" should not be trusted.
namespace audio::alc5663 {
// Register values used by clock dividers in the ALC5663.
enum class ClockDivisionRate {
DivideBy1 = 0, // Disable divider.
DivideBy2 = 1,
DivideBy3 = 2,
DivideBy4 = 3,
DivideBy6 = 4,
DivideBy8 = 5,
DivideBy12 = 6,
DivideBy16 = 7,
};
// Any write to this register will trigger a reset of the codec.
struct ResetAndDeviceIdReg {
uint16_t data;
DEF_SUBBIT(data, 1, device_id); // Device ID: Reading 0 indicates ALC5663.
static constexpr uint16_t kAddress = 0x0;
};
// Sidetone (repeating mic signal into speaker output) control and configuration.
struct SidetoneControlReg {
uint16_t data;
DEF_SUBFIELD(data, 15, 13, sidetone_hpf_fc_s); // Highpass filter cutoff (R/W)
DEF_SUBBIT(data, 12, sidetone_hpf_en); // Enable sidetone highpass filter (R/W)
DEF_SUBBIT(data, 6, en_sidetone); // Enable sidetone (R/W)
DEF_SUBBIT(data, 5, sidetone_boost_sel); // Sidetone gain (R/W)
DEF_SUBFIELD(data, 4, 0, sidetone_vol_sel); // Sidetone volume (R/W)
static constexpr uint16_t kAddress = 0x18;
};
// Stereo DAC digital volume.
//
// Digital volume can be set from 0 (-65.625dB) to 0xaf (0dB) with
// 0.375dB per step.
struct StereoDacDigitalVolumeReg {
uint16_t data;
DEF_SUBFIELD(data, 15, 8, vol_dac1_l); // Left channel digital volume
DEF_SUBFIELD(data, 7, 0, vol_dac1_r); // Right channel digital volume
static constexpr uint8_t kMinVolume = 0x00;
// Volume we set the hardware to. (-6.0dB).
static constexpr uint8_t kTargetVolume = 0x9f;
// Max volume according to the ALC5663 datasheet.
//
// While we should be able to run with no digital volume change, in practice, we have observed
// distortion of the signal with values this high. We use kTargetVolume instead.
static constexpr uint8_t kHardwareMaxVolume = 0xaf;
static constexpr uint16_t kAddress = 0x19;
};
// Stereo DAC Digital Mixer Control.
struct StereoDacDigitalMixerControl {
uint16_t data;
DEF_SUBBIT(data, 15, mute_dacl1_mixl); // Mute DACL to DAC Mixer L
DEF_SUBBIT(data, 14, gain_dacl1_to_stereo_l); // Apply -6dB gain from DAC L to DAC Mixer L
DEF_SUBBIT(data, 13, mute_dacr1_mixl); // Mute DACR to DAC Mixer L
DEF_SUBBIT(data, 12, gain_dacr1_to_stereo_l); // Apply -6dB gain from DAC R to DAC Mixer L
DEF_SUBBIT(data, 7, mute_dacl1_mixr); // Mute DACL to DAC Mixer R
DEF_SUBBIT(data, 6, gain_dacl1_to_stereo_r); // Apply -6dB gain from DAC L to DAC Mixer R
DEF_SUBBIT(data, 5, mute_dacr1_mixr); // Mute DACR to DAC Mixer R
DEF_SUBBIT(data, 4, gain_dacr1_to_stereo_r); // Apply -6dB gain from DAC R to DAC Mixer R
static constexpr uint16_t kAddress = 0x2a;
};
struct BypassStereoDacMixerControlReg {
uint16_t data;
DEF_SUBBIT(data, 3, dacl1_source); // Select DACL Source. (0 == bypass mixers, 1 == use mixers)
DEF_SUBBIT(data, 2, dacr1_source); // Select DACR Source. (0 == bypass mixers, 1 == use mixers)
static constexpr uint16_t kAddress = 0x2d;
};
struct PowerManagementControl1Reg {
uint16_t data;
DEF_SUBBIT(data, 15, en_i2s1); // I2S 1 digital interface power (R/W)
DEF_SUBBIT(data, 11, pow_dac_l_1); // Analog DAC L1 power (R/W)
DEF_SUBBIT(data, 10, pow_dac_r_1); // Analog DAC R1 power (R/W)
DEF_SUBBIT(data, 8, pow_ldo_adcref); // ADC REF LDO power (R/W)
DEF_SUBBIT(data, 5, fast_ldo_adcref);
DEF_SUBBIT(data, 4, pow_adc_l); // Analog ADC power (R/W)
static constexpr uint16_t kAddress = 0x61;
};
struct PowerManagementControl2Reg {
uint16_t data;
DEF_SUBBIT(data, 15, pow_adc_filter); // ADC digital filter power (R/W)
DEF_SUBBIT(data, 10, pow_dac_stereo1_filter); // DAC stereo 1 filter power (R/W)
static constexpr uint16_t kAddress = 0x62;
};
struct PowerManagementControl3Reg {
uint16_t data;
DEF_SUBBIT(data, 15, pow_vref1); // VREF1 power (R/W)
DEF_SUBBIT(data, 14, en_fastb1);
DEF_SUBBIT(data, 13, pow_vref2); // VREF2 power (R/W)
DEF_SUBBIT(data, 12, en_fastb2);
DEF_SUBBIT(data, 9, pow_main_bias); // MBIAS power (R/W)
DEF_SUBBIT(data, 7, pow_bg_bias); // MBIAS bandgap power (R/W)
DEF_SUBBIT(data, 5, en_l_hp); // Left headphone amp power (R/W)
DEF_SUBBIT(data, 4, en_r_hp); // Right headphone amp power (R/W)
DEF_SUBFIELD(data, 3, 2, en_amp_hp);
DEF_SUBFIELD(data, 1, 0, ldo1_dvo);
static constexpr uint16_t kAddress = 0x63;
};
struct PowerManagementControl4Reg {
uint16_t data;
DEF_SUBBIT(data, 15, pow_bst1); // MIC BST1 power (R/W)
DEF_SUBBIT(data, 11, pow_micbias1); // MICBIAS1 power (R/W)
DEF_SUBBIT(data, 10, pow_micbias2); // MICBIAS2 power (R/W)
DEF_SUBBIT(data, 1, pow_recmix1); // RECMIX power (R/W)
static constexpr uint16_t kAddress = 0x64;
};
struct PowerManagementControl5Reg {
uint16_t data;
DEF_SUBBIT(data, 6, pow_pll); // PLL power (R/W)
static constexpr uint16_t kAddress = 0x65;
};
struct PowerManagementControlMisc {
uint16_t data;
static constexpr uint16_t kEnable = 0xef;
DEF_SUBFIELD(data, 15, 8, gating); // Clock gating (??)
static constexpr uint16_t kAddress = 0x6e;
};
struct I2s1DigitalInterfaceControlReg {
uint16_t data;
// If (1), we read BCLK from the bus ("slave mode" in manual).
// If (0), we write BCKL to the bus ("master mode" in manual).
DEF_SUBBIT(data, 15, i2s1_externally_clocked);
// Configure the I2S1 ADCDAT pin as an output pin (0) or input pin (1).
DEF_SUBBIT(data, 14, i2s1_adcdac);
// I2S1 input/output data compression.
DEF_SUBFIELD(data, 13, 12, i2s1_out_comp);
DEF_SUBFIELD(data, 11, 10, i2s1_in_comp);
DEF_SUBBIT(data, 8, inverted_i2s1_bclk); // I2S1 BCLK polarity. Normal (0) or inverted (1).
DEF_SUBBIT(data, 6, i2s1_mono);
// I2S1 Data Length
enum class DataLength {
Bits16 = 0,
Bits20 = 1,
Bits24 = 2,
Bits8 = 3,
};
DEF_ENUM_SUBFIELD(data, DataLength, 5, 4, i2s1_data_length);
// I2S1 Data Format
enum class DataFormat {
I2sFormat = 0,
LeftJustified = 1,
};
DEF_ENUM_SUBFIELD(data, DataFormat, 2, 0, i2s1_data_format);
static constexpr uint16_t kAddress = 0x70;
};
struct AdcDacClockControlReg {
uint16_t data;
// I2S Clock Pre-Divider (from clk_sys_pre to clk_sys_i2s).
DEF_ENUM_SUBFIELD(data, ClockDivisionRate, 14, 12, i2s_pre_div);
// Clock configuration for I2S master mode.
DEF_ENUM_SUBFIELD(data, ClockDivisionRate, 10, 8, master_i2s_div);
DEF_SUBFIELD(data, 5, 4, master_clk_source);
DEF_SUBFIELD(data, 3, 2, dac_oversample_rate); // Stereo DAC oversample rate
DEF_SUBFIELD(data, 1, 0, adc_oversample_rate); // Mono ADC oversample rate
static constexpr uint16_t kAddress = 0x73;
};
struct GlobalClockControlReg {
uint16_t data;
// System clock source.
enum class SysClk1Source : uint8_t {
MCLK = 0,
PLL = 1,
InternalClock = 2,
};
DEF_ENUM_SUBFIELD(data, SysClk1Source, 15, 14, sysclk1_source);
// PLL source.
enum class PllSource : uint8_t {
MCLK = 0,
BCLK = 1,
InternalClock = 4,
};
DEF_ENUM_SUBFIELD(data, PllSource, 13, 11, pll_source);
// PLL pre-divider.
// 0: divide by 1 (i.e., disabled).
// 1: divide by 2.
DEF_SUBBIT(data, 3, pll_pre_div);
// System clock divider for Stereo DAC and Mono ADC filters.
DEF_ENUM_SUBFIELD(data, ClockDivisionRate, 2, 0, filter_clock_divider);
static constexpr uint16_t kAddress = 0x80;
};
// Phase-locked loop registers.
//
// The PLL takes an input F_in (from MCLK, BLCK, or Internal Clock; determined by
// GlobalClockControlReg::pll_div) and outputs a clock with frequency F_out:
//
// F_out = (F_in * (N + 2)) / ((M + 2) * (K + 2))
//
// The ALC5663 manual states outputs should be in the range 2.048MHz to 40MHz,
// and that K is typically 2.
struct PllControl1Reg {
uint16_t data;
DEF_SUBFIELD(data, 15, 7, n_code); // Value for "N".
DEF_SUBFIELD(data, 4, 0, k_code); // Value for "K".
static constexpr uint16_t kAddress = 0x81;
};
struct PllControl2Reg {
uint16_t data;
DEF_SUBFIELD(data, 15, 12, m_code); // Value for "M".
DEF_SUBBIT(data, 11, bypass_m); // Ignore the (M + 2) factor.
DEF_SUBBIT(data, 10, bypass_k); // Ignore the (K + 2) factor.
static constexpr uint16_t kAddress = 0x82;
};
// Control registers for ALC5663's asynchronous sampling rate converter
// (ASRC), allowing a system clock that is independent of the I2S BCLK.
struct AsrcControl1Reg {
uint16_t data;
DEF_SUBBIT(data, 11, i2s1_asrc); // Enable global ASRC
DEF_SUBBIT(data, 10, dac_asrc); // Enable ASRC for D->A path.
DEF_SUBBIT(data, 3, adc_asrc); // Enable ASRC for A->D path.
static constexpr uint16_t kAddress = 0x83;
};
struct AsrcControl2Reg {
uint16_t data;
enum class FilterSource : uint8_t {
ClkSys = 0, // Use clk_sys_i2s (after it has been divided by MX-0080[2:0].)
ASRC = 1, // Use the clock from the ASRC block.
};
// Clock source for the D->A filter.
DEF_ENUM_SUBFIELD(data, FilterSource, 14, 12, clk_da_filter_source);
// Clock source for the A->D filter.
DEF_ENUM_SUBFIELD(data, FilterSource, 2, 0, clk_ad_filter_source);
static constexpr uint16_t kAddress = 0x84;
};
struct AsrcControl4Reg {
uint16_t data;
static constexpr uint32_t kSampleRate48000 = 0x2;
DEF_SUBFIELD(data, 5, 4, asrc_i2s1_mode); // ASRC clock source / I2S rate (??)
static constexpr uint16_t kAddress = 0x86;
};
// Output amplifier.
struct HpAmpControl1Reg {
uint16_t data;
DEF_SUBBIT(data, 13, enable_l_hp); // Enable left channel HP output (??)
DEF_SUBBIT(data, 12, enable_r_hp); // Enable right channel HP output (??)
DEF_SUBBIT(data, 5, pow_pump_l_hp); // Left charge pump power
DEF_SUBBIT(data, 4, pow_pump_r_hp); // Right charge pump power
DEF_SUBBIT(data, 1, pow_capless_l); // Left capless block power
DEF_SUBBIT(data, 0, pow_capless_r); // Right capless block power
static constexpr uint16_t kAddress = 0x8e;
};
struct HpAmpControl2Reg {
uint16_t data;
DEF_SUBBIT(data, 11, output_l_hp); // Enable capless HP L output
DEF_SUBBIT(data, 10, output_r_hp); // Enable capless HP R output
// Overcurrent protection (OCP).
DEF_SUBBIT(data, 2, overcurrent_protection_hp); // Enable HP OCP
DEF_SUBFIELD(data, 1, 0, overcurrent_limit_hp); // HP OCP threshold
static constexpr uint16_t kAddress = 0x91;
};
struct HpAmpControl3Reg {
uint16_t data;
DEF_SUBBIT(data, 9, pow_reg_l_hp); // HP AMP L VEE regulator power
DEF_SUBBIT(data, 8, pow_reg_r_hp); // HP AMP R VEE regulator power
static constexpr uint16_t kAddress = 0x92;
};
struct InternalClockControlReg {
uint16_t data;
DEF_SUBBIT(data, 9, pow_clock_25mhz); // Enable 25MHz internal clock.
DEF_SUBBIT(data, 8, pow_clock_1mhz); // Enable 1MHz internal clock.
static constexpr uint16_t kAddress = 0x94;
};
struct GeneralControlReg {
uint16_t data;
DEF_SUBBIT(data, 0, digital_gate_ctrl); // MCLK gating.
static constexpr uint16_t kAddress = 0xfa;
};
struct VersionIdReg {
uint16_t data;
DEF_SUBFIELD(data, 15, 0, version_id);
static constexpr uint16_t kAddress = 0xfd;
};
struct VendorIdReg {
uint16_t data;
static const uint16_t kVendorRealtek = 0x10ec;
DEF_SUBFIELD(data, 15, 0, vendor_id);
static constexpr uint16_t kAddress = 0xfe;
};
struct DacRefLdoControlReg {
uint16_t data;
DEF_SUBBIT(data, 9, pow_ldo_dacrefl); // Power DACREF L LDO
DEF_SUBBIT(data, 1, pow_ldo_dacrefr); // Power DACREF R LDO
static constexpr uint16_t kAddress = 0x112;
};
} // namespace audio::alc5663
#endif // SRC_MEDIA_AUDIO_DRIVERS_CODECS_ALC5663_ALC5663_REGISTERS_H_