use embedded_hal::i2c::I2c;
use rusty_esp_core::error::{Error, Result};
use super::{Bits, CodecChip, I2cRegs, I2sFormat, Mode, Module};
pub const ADDR: u8 = 0x18;
pub const CHIP_ID: (u8, u8) = (0x83, 0x11);
#[allow(missing_docs)]
pub mod reg {
pub const RESET_REG00: u8 = 0x00;
pub const CLK_MANAGER_REG01: u8 = 0x01;
pub const CLK_MANAGER_REG02: u8 = 0x02;
pub const CLK_MANAGER_REG03: u8 = 0x03;
pub const CLK_MANAGER_REG04: u8 = 0x04;
pub const CLK_MANAGER_REG05: u8 = 0x05;
pub const CLK_MANAGER_REG06: u8 = 0x06;
pub const CLK_MANAGER_REG07: u8 = 0x07;
pub const CLK_MANAGER_REG08: u8 = 0x08;
pub const SDPIN_REG09: u8 = 0x09;
pub const SDPOUT_REG0A: u8 = 0x0A;
pub const SYSTEM_REG0B: u8 = 0x0B;
pub const SYSTEM_REG0C: u8 = 0x0C;
pub const SYSTEM_REG0D: u8 = 0x0D;
pub const SYSTEM_REG0E: u8 = 0x0E;
pub const SYSTEM_REG0F: u8 = 0x0F;
pub const SYSTEM_REG10: u8 = 0x10;
pub const SYSTEM_REG11: u8 = 0x11;
pub const SYSTEM_REG12: u8 = 0x12;
pub const SYSTEM_REG13: u8 = 0x13;
pub const SYSTEM_REG14: u8 = 0x14;
pub const ADC_REG15: u8 = 0x15;
pub const ADC_REG16: u8 = 0x16;
pub const ADC_REG17: u8 = 0x17;
pub const ADC_REG18: u8 = 0x18;
pub const ADC_REG19: u8 = 0x19;
pub const ADC_REG1A: u8 = 0x1A;
pub const ADC_REG1B: u8 = 0x1B;
pub const ADC_REG1C: u8 = 0x1C;
pub const DAC_REG31: u8 = 0x31;
pub const DAC_REG32: u8 = 0x32;
pub const DAC_REG33: u8 = 0x33;
pub const DAC_REG34: u8 = 0x34;
pub const DAC_REG35: u8 = 0x35;
pub const DAC_REG37: u8 = 0x37;
pub const GPIO_REG44: u8 = 0x44;
pub const GP_REG45: u8 = 0x45;
pub const CHD1_REGFD: u8 = 0xFD;
pub const CHD2_REGFE: u8 = 0xFE;
pub const CHVER_REGFF: u8 = 0xFF;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Coeff {
pub mclk: u32,
pub rate: u32,
pub pre_div: u8,
pub pre_multi: u8,
pub adc_div: u8,
pub dac_div: u8,
pub fs_mode: u8,
pub lrck_h: u8,
pub lrck_l: u8,
pub bclk_div: u8,
pub adc_osr: u8,
pub dac_osr: u8,
}
#[allow(clippy::too_many_arguments)]
const fn c(
mclk: u32,
rate: u32,
pre_div: u8,
pre_multi: u8,
adc_div: u8,
dac_div: u8,
fs_mode: u8,
lrck_h: u8,
lrck_l: u8,
bclk_div: u8,
adc_osr: u8,
dac_osr: u8,
) -> Coeff {
Coeff {
mclk,
rate,
pre_div,
pre_multi,
adc_div,
dac_div,
fs_mode,
lrck_h,
lrck_l,
bclk_div,
adc_osr,
dac_osr,
}
}
pub const COEFF: &[Coeff] = &[
c(
12_288_000, 8000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
18_432_000, 8000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10, 0x20,
),
c(
16_384_000, 8000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
8_192_000, 8000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
6_144_000, 8000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
4_096_000, 8000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
3_072_000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
2_048_000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
1_536_000, 8000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
1_024_000, 8000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
11_289_600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
5_644_800, 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
2_822_400, 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
1_411_200, 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
12_288_000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
6_144_000, 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
3_072_000, 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
1_536_000, 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
12_288_000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
18_432_000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x20,
),
c(
16_384_000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
8_192_000, 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
6_144_000, 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
4_096_000, 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
3_072_000, 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
2_048_000, 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
1_536_000, 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
1_024_000, 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x20,
),
c(
11_289_600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
5_644_800, 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
2_822_400, 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_411_200, 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
12_288_000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
18_432_000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
6_144_000, 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
3_072_000, 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_536_000, 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
12_288_000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
18_432_000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10,
),
c(
16_384_000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
8_192_000, 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
6_144_000, 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
4_096_000, 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
3_072_000, 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
2_048_000, 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_536_000, 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10,
),
c(
1_024_000, 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
11_289_600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
5_644_800, 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
2_822_400, 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_411_200, 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
12_288_000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
18_432_000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
6_144_000, 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
3_072_000, 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_536_000, 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
12_288_000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
18_432_000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10,
),
c(
16_384_000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
8_192_000, 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
6_144_000, 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10,
),
c(
4_096_000, 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
3_072_000, 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10,
),
c(
2_048_000, 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_536_000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18,
),
c(
1_024_000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10,
),
c(
11_289_600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
5_644_800, 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
2_822_400, 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_411_200, 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10,
),
c(
12_288_000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
18_432_000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
6_144_000, 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
3_072_000, 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10,
),
c(
1_536_000, 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10,
),
];
#[must_use]
pub fn coeff(mclk_hz: u32, rate_hz: u32) -> Option<&'static Coeff> {
COEFF
.iter()
.find(|c| c.mclk == mclk_hz && c.rate == rate_hz)
}
#[must_use]
pub const fn mclk_for(rate_hz: u32) -> u32 {
rate_hz * 256
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MclkSource {
Pin,
Sclk,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum MicGain {
Db0 = 0,
Db6 = 1,
Db12 = 2,
Db18 = 3,
Db24 = 4,
Db30 = 5,
Db36 = 6,
Db42 = 7,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Config {
pub mode: Mode,
pub mclk: MclkSource,
pub invert_mclk: bool,
pub invert_sclk: bool,
pub dmic: bool,
pub sample_rate_hz: u32,
pub mclk_hz: u32,
}
impl Config {
#[must_use]
pub const fn slave(sample_rate_hz: u32) -> Self {
Config {
mode: Mode::Slave,
mclk: MclkSource::Pin,
invert_mclk: false,
invert_sclk: false,
dmic: false,
sample_rate_hz,
mclk_hz: mclk_for(sample_rate_hz),
}
}
}
#[must_use]
pub const fn dac_volume_reg(half_db: i16) -> u8 {
let v = 0xBF + half_db as i32;
if v < 0 {
0
} else if v > 0xFF {
0xFF
} else {
v as u8
}
}
#[derive(Debug)]
pub struct Es8311<I> {
regs: I2cRegs<I>,
dmic: bool,
mclk: MclkSource,
}
impl<I: I2c> Es8311<I> {
pub fn new(i2c: I, addr: u8) -> Self {
Es8311 {
regs: I2cRegs::new(i2c, addr),
dmic: false,
mclk: MclkSource::Pin,
}
}
pub fn release(self) -> I {
self.regs.release()
}
pub fn regs(&mut self) -> &mut I2cRegs<I> {
&mut self.regs
}
pub fn chip_id(&mut self) -> Result<(u8, u8)> {
Ok((
self.regs.read(reg::CHD1_REGFD)?,
self.regs.read(reg::CHD2_REGFE)?,
))
}
pub fn init(&mut self, cfg: &Config) -> Result<()> {
self.dmic = cfg.dmic;
self.mclk = cfg.mclk;
let r = &mut self.regs;
r.write(reg::GPIO_REG44, 0x08)?;
r.write(reg::GPIO_REG44, 0x08)?;
r.write(reg::CLK_MANAGER_REG01, 0x30)?;
r.write(reg::CLK_MANAGER_REG02, 0x00)?;
r.write(reg::CLK_MANAGER_REG03, 0x10)?;
r.write(reg::ADC_REG16, 0x24)?;
r.write(reg::CLK_MANAGER_REG04, 0x10)?;
r.write(reg::CLK_MANAGER_REG05, 0x00)?;
r.write(reg::SYSTEM_REG0B, 0x00)?;
r.write(reg::SYSTEM_REG0C, 0x00)?;
r.write(reg::SYSTEM_REG10, 0x1F)?;
r.write(reg::SYSTEM_REG11, 0x7F)?;
r.write(reg::RESET_REG00, 0x80)?;
let mut regv = r.read(reg::RESET_REG00)?;
match cfg.mode {
Mode::Master => regv |= 0x40,
Mode::Slave => regv &= 0xBF,
}
r.write(reg::RESET_REG00, regv)?;
r.write(reg::CLK_MANAGER_REG01, 0x3F)?;
let mut regv = r.read(reg::CLK_MANAGER_REG01)?;
match cfg.mclk {
MclkSource::Pin => regv &= 0x7F,
MclkSource::Sclk => regv |= 0x80,
}
r.write(reg::CLK_MANAGER_REG01, regv)?;
self.set_sample_rate(cfg.sample_rate_hz, cfg.mclk_hz)?;
let r = &mut self.regs;
let mut regv = r.read(reg::CLK_MANAGER_REG01)?;
if cfg.invert_mclk {
regv |= 0x40;
} else {
regv &= !0x40;
}
r.write(reg::CLK_MANAGER_REG01, regv)?;
let mut regv = r.read(reg::CLK_MANAGER_REG06)?;
if cfg.invert_sclk {
regv |= 0x20;
} else {
regv &= !0x20;
}
r.write(reg::CLK_MANAGER_REG06, regv)?;
r.write(reg::SYSTEM_REG13, 0x10)?;
r.write(reg::ADC_REG1B, 0x0A)?;
r.write(reg::ADC_REG1C, 0x6A)?;
Ok(())
}
pub fn set_dac_volume_reg(&mut self, value: u8) -> Result<()> {
self.regs.write(reg::DAC_REG32, value)
}
pub fn set_mic_gain(&mut self, gain: MicGain) -> Result<()> {
self.regs.write(reg::ADC_REG16, gain as u8)
}
}
impl<I: I2c> CodecChip for Es8311<I> {
fn set_sample_rate(&mut self, sample_rate_hz: u32, mclk_hz: u32) -> Result<()> {
let c = coeff(mclk_hz, sample_rate_hz).ok_or(Error::Unsupported)?;
let r = &mut self.regs;
let mut regv = r.read(reg::CLK_MANAGER_REG02)? & 0x07;
regv |= (c.pre_div - 1) << 5;
let mut datmp: u8 = match c.pre_multi {
1 => 0,
2 => 1,
4 => 2,
8 => 3,
_ => 0,
};
if self.mclk == MclkSource::Sclk {
datmp = if sample_rate_hz == 8000 { 2 } else { 3 };
}
regv |= datmp << 3;
r.write(reg::CLK_MANAGER_REG02, regv)?;
let regv = ((c.adc_div - 1) << 4) | (c.dac_div - 1);
r.write(reg::CLK_MANAGER_REG05, regv)?;
let mut regv = r.read(reg::CLK_MANAGER_REG03)? & 0x80;
regv |= c.fs_mode << 6;
regv |= c.adc_osr;
r.write(reg::CLK_MANAGER_REG03, regv)?;
let mut regv = r.read(reg::CLK_MANAGER_REG04)? & 0x80;
regv |= c.dac_osr;
r.write(reg::CLK_MANAGER_REG04, regv)?;
let mut regv = r.read(reg::CLK_MANAGER_REG07)? & 0xC0;
regv |= c.lrck_h;
r.write(reg::CLK_MANAGER_REG07, regv)?;
r.write(reg::CLK_MANAGER_REG08, c.lrck_l)?;
let mut regv = r.read(reg::CLK_MANAGER_REG06)? & 0xE0;
regv |= if c.bclk_div < 19 {
c.bclk_div - 1
} else {
c.bclk_div
};
r.write(reg::CLK_MANAGER_REG06, regv)
}
fn set_format(&mut self, fmt: I2sFormat, bits: Bits) -> Result<()> {
let r = &mut self.regs;
let mut dac = r.read(reg::SDPIN_REG09)?;
let mut adc = r.read(reg::SDPOUT_REG0A)?;
match fmt {
I2sFormat::Standard => {
dac &= 0xFC;
adc &= 0xFC;
}
I2sFormat::LeftJustified => {
dac = (dac & 0xFC) | 0x01;
adc = (adc & 0xFC) | 0x01;
}
I2sFormat::Dsp => {
dac = (dac & 0xDC) | 0x03;
adc = (adc & 0xDC) | 0x03;
}
}
r.write(reg::SDPIN_REG09, dac)?;
r.write(reg::SDPOUT_REG0A, adc)?;
let mut dac = r.read(reg::SDPIN_REG09)?;
let mut adc = r.read(reg::SDPOUT_REG0A)?;
match bits {
Bits::B16 => {
dac |= 0x0C;
adc |= 0x0C;
}
Bits::B24 => {}
Bits::B32 => {
dac |= 0x10;
adc |= 0x10;
}
}
r.write(reg::SDPIN_REG09, dac)?;
r.write(reg::SDPOUT_REG0A, adc)
}
fn start(&mut self, module: Module) -> Result<()> {
let r = &mut self.regs;
let mut dac = (r.read(reg::SDPIN_REG09)? & 0xBF) | 0x40;
let mut adc = (r.read(reg::SDPOUT_REG0A)? & 0xBF) | 0x40;
if matches!(module, Module::Adc | Module::AdcDac) {
adc &= !0x40;
}
if matches!(module, Module::Dac | Module::AdcDac) {
dac &= !0x40;
}
r.write(reg::SDPIN_REG09, dac)?;
r.write(reg::SDPOUT_REG0A, adc)?;
r.write(reg::ADC_REG17, 0xBF)?;
r.write(reg::SYSTEM_REG0E, 0x02)?;
r.write(reg::SYSTEM_REG12, 0x00)?;
r.write(reg::SYSTEM_REG14, 0x1A)?;
let mut regv = r.read(reg::SYSTEM_REG14)?;
if self.dmic {
regv |= 0x40;
} else {
regv &= !0x40;
}
r.write(reg::SYSTEM_REG14, regv)?;
r.write(reg::SYSTEM_REG0D, 0x01)?;
r.write(reg::ADC_REG15, 0x40)?;
r.write(reg::DAC_REG37, 0x08)?;
r.write(reg::GP_REG45, 0x00)?;
r.write(reg::GPIO_REG44, 0x58)
}
fn stop(&mut self) -> Result<()> {
let r = &mut self.regs;
r.write(reg::DAC_REG32, 0x00)?;
r.write(reg::ADC_REG17, 0x00)?;
r.write(reg::SYSTEM_REG0E, 0xFF)?;
r.write(reg::SYSTEM_REG12, 0x02)?;
r.write(reg::SYSTEM_REG14, 0x00)?;
r.write(reg::SYSTEM_REG0D, 0xFA)?;
r.write(reg::ADC_REG15, 0x00)?;
r.write(reg::GP_REG45, 0x01)
}
fn set_mute(&mut self, mute: bool) -> Result<()> {
let regv = self.regs.read(reg::DAC_REG31)? & 0x9F;
self.regs
.write(reg::DAC_REG31, if mute { regv | 0x60 } else { regv })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::chip::fake::FakeCodec;
#[test]
fn coefficient_table_is_complete_and_findable() {
assert_eq!(COEFF.len(), 75, "the vendor table's 75 rows");
assert!(coeff(4_096_000, 16000).is_some());
assert!(coeff(12_288_000, 48000).is_some());
assert!(coeff(4_096_000, 48000).is_none());
assert_eq!(mclk_for(16000), 4_096_000);
for c in COEFF {
assert!((1..=8).contains(&c.pre_div), "{c:?}");
assert!(matches!(c.pre_multi, 1 | 2 | 4 | 8), "{c:?}");
assert!(c.adc_div >= 1 && c.dac_div >= 1, "{c:?}");
}
}
#[test]
fn volume_register_is_half_db_from_zero_at_bf() {
assert_eq!(dac_volume_reg(0), 0xBF);
assert_eq!(dac_volume_reg(64), 0xFF);
assert_eq!(dac_volume_reg(65), 0xFF);
assert_eq!(dac_volume_reg(-191), 0x00);
assert_eq!(dac_volume_reg(-200), 0x00);
assert_eq!(dac_volume_reg(-100), 0x5B, "the driver's -50 dB point");
}
#[test]
fn init_reproduces_the_vendor_sequence() {
let mut chip = Es8311::new(FakeCodec::default(), ADDR);
chip.init(&Config::slave(16_000)).unwrap();
let bus = chip.release();
assert_eq!(bus.addr_seen, Some(0x18));
let expected: &[(u8, u8)] = &[
(0x44, 0x08),
(0x44, 0x08),
(0x01, 0x30),
(0x02, 0x00),
(0x03, 0x10),
(0x16, 0x24),
(0x04, 0x10),
(0x05, 0x00),
(0x0B, 0x00),
(0x0C, 0x00),
(0x10, 0x1F),
(0x11, 0x7F),
(0x00, 0x80),
(0x00, 0x80), (0x01, 0x3F),
(0x01, 0x3F), (0x02, 0x00),
(0x05, 0x00),
(0x03, 0x10),
(0x04, 0x20), (0x07, 0x00),
(0x08, 0xFF),
(0x06, 0x03),
(0x01, 0x3F), (0x06, 0x03), (0x13, 0x10),
(0x1B, 0x0A),
(0x1C, 0x6A),
];
assert_eq!(bus.writes, expected);
}
#[test]
fn master_mode_and_sclk_derived_mclk_set_their_bits() {
let mut chip = Es8311::new(FakeCodec::default(), ADDR);
chip.init(&Config {
mode: Mode::Master,
mclk: MclkSource::Sclk,
invert_mclk: true,
invert_sclk: true,
dmic: true,
sample_rate_hz: 8000,
mclk_hz: mclk_for(8000),
})
.unwrap();
let bus = chip.release();
assert_eq!(bus.reg(0x00), 0xC0, "master bit on top of the reset value");
assert_eq!(bus.reg(0x01), 0xFF, "MCLK from BCLK, inverted");
assert_eq!(bus.reg(0x02), 2 << 3);
assert!(bus.reg(0x06) & 0x20 != 0, "BCLK inverted");
assert_eq!(bus.reg(0x1C), 0x6A);
}
#[test]
fn format_start_stop_mute_and_gain() {
let mut chip = Es8311::new(FakeCodec::default(), ADDR);
chip.init(&Config::slave(48_000)).unwrap();
chip.set_format(I2sFormat::Standard, Bits::B16).unwrap();
chip.start(Module::AdcDac).unwrap();
{
let bus = chip.regs().bus();
assert_eq!(bus.reg(0x09) & 0x4F, 0x0C, "DAC port: 16-bit, unmuted");
assert_eq!(bus.reg(0x0A) & 0x4F, 0x0C, "ADC port: 16-bit, unmuted");
assert_eq!(bus.reg(0x14), 0x1A, "analog mic, PGA on");
assert_eq!(bus.reg(0x44), 0x58);
assert_eq!(bus.reg(0x45), 0x00);
}
chip.set_format(I2sFormat::Dsp, Bits::B32).unwrap();
chip.start(Module::Dac).unwrap();
{
let bus = chip.regs().bus();
assert_eq!(bus.reg(0x09) & 0x53, 0x13, "DAC: DSP, 32-bit, on");
assert_eq!(
bus.reg(0x0A) & 0x40,
0x40,
"ADC port muted when only the DAC starts"
);
}
chip.set_mute(true).unwrap();
assert_eq!(chip.regs().bus().reg(0x31) & 0x60, 0x60);
chip.set_mute(false).unwrap();
assert_eq!(chip.regs().bus().reg(0x31) & 0x60, 0x00);
chip.set_mic_gain(MicGain::Db24).unwrap();
chip.set_dac_volume_reg(dac_volume_reg(-12)).unwrap();
chip.stop().unwrap();
let bus = chip.release();
assert_eq!(bus.reg(0x16), 4);
assert_eq!(
bus.history(0x32),
[0xB3, 0x00],
"volume then the suspend's zero"
);
assert_eq!(bus.reg(0x0D), 0xFA);
assert_eq!(bus.reg(0x45), 0x01);
assert_eq!(bus.reg(0x0E), 0xFF);
}
#[test]
fn unsupported_clock_pair_is_refused_before_any_write() {
let mut chip = Es8311::new(FakeCodec::default(), ADDR);
assert_eq!(
chip.set_sample_rate(44_100, 4_096_000),
Err(Error::Unsupported)
);
assert!(chip.release().writes.is_empty());
}
#[test]
fn chip_id_reads_the_id_registers() {
let mut chip = Es8311::new(
FakeCodec::with_defaults(&[(0xFD, 0x83), (0xFE, 0x11)]),
ADDR,
);
assert_eq!(chip.chip_id().unwrap(), CHIP_ID);
}
}