start at TLV320AIC2354 driver

This commit is contained in:
Laila van Reenen 2025-06-15 00:23:43 +02:00
commit 03d37ac9b4
Signed by: LailaTheElf
GPG Key ID: 8A3EF0226518C12D
5 changed files with 723 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

65
Cargo.lock generated Normal file
View File

@ -0,0 +1,65 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "TLV320AIC2354"
version = "0.1.0"
dependencies = [
"with_builtin_macros",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "with_builtin_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24deb3cd6e530e7617b12b1f0f1ce160a3a71d92feb351c4db5156d1d10e398a"
dependencies = [
"with_builtin_macros-proc_macros",
]
[[package]]
name = "with_builtin_macros-proc_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2259ae9b1285596f1ee52ce8f627013c65853d4d7f271cb10bfe2d048769804a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

7
Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "TLV320AIC2354"
version = "0.1.0"
edition = "2024"
[dependencies]
with_builtin_macros = "0.1.0"

8
src/lib.rs Normal file
View File

@ -0,0 +1,8 @@
mod registers;
fn i2c_read(page: u16, reg: u16) -> Result<u16, _>{
Err(())
}
fn i2c_write(page: u16, reg: u16, value: u16) -> Result<(), _>{
Err(())
}

642
src/registers.rs Normal file
View File

@ -0,0 +1,642 @@
mod regs {
use with_builtin_macros::with_builtin;
trait RegisterRW {
const PAGE: u8;
const REG: u8;
fn get_reg(&self) -> u8;
fn set_reg(&mut self, value: u8);
fn load(&mut self) {
println!("load reg {} from page {}", Self::REG, Self::PAGE);
todo!();
}
fn store(&mut self) {
println!("store reg {} from page {}", Self::REG, Self::PAGE);
todo!();
}
}
trait RegisterRO {
const PAGE: u8;
const REG: u8;
fn get_reg(&self) -> u8;
fn load(&mut self) {
println!("load reg {} from page {}", Self::REG, Self::PAGE);
todo!();
}
}
trait RegisterWO {
const PAGE: u8;
const REG: u8;
fn set_reg(&mut self, value: u8);
fn store(&mut self) {
println!("store reg {} from page {}", Self::REG, Self::PAGE);
todo!();
}
}
macro_rules! register_rw {
($name:ident, $page:expr, $reg:expr) => {
struct $name {
value: u8,
changed: bool
}
impl RegisterRW for $name {
const PAGE: u8 = $page;
const REG: u8 = $reg;
fn get_reg(&self) -> u8 {
self.value
}
fn set_reg(&mut self, value: u8) {
if self.value != value {
self.changed = true;
}
self.value = value;
}
fn load(&mut self) {
self.changed = false;
todo!();
}
fn store(&mut self) {
self.changed = false;
todo!();
}
}
};
}
macro_rules! register_ro {
($name:ident, $page:expr, $reg:expr) => {
struct $name {
value: u8,
}
impl RegisterRO for $name {
const PAGE: u8 = $page;
const REG: u8 = $reg;
fn get_reg(&self) -> u8 {
self.value
}
fn load(&mut self) {
todo!();
}
}
};
}
macro_rules! register_wo {
($name:ident, $page:expr, $reg:expr) => {
struct $name {
value: u8,
changed: bool
}
impl RegisterWO for $name {
const PAGE: u8 = $page;
const REG: u8 = $reg;
fn set_reg(&mut self, value: u8) {
self.changed = true;
self.value = value;
}
fn store(&mut self) {
self.changed = false;
todo!();
}
}
};
}
macro_rules! bitmask_rw {
($name:ident, $mask:expr, $shift:expr) => {
with_builtin!(let $fname = concat_idents!(get_, $name) in {
fn $fname (&mut self, $name: u8) {
self.value = (($name << $shift) & $mask) | (self.value & !$mask);
}
});
with_builtin!(let $fname = concat_idents!(set_, $name) in {
fn $fname (&mut self) -> u8 {
(self.value & $mask) >> $shift
}
});
};
}
macro_rules! bitmask_ro {
($name:ident, $mask:expr, $shrift:expr) => {
with_builtin!(let $fname = concat_idents!(get_, $name) in {
fn $fname (&mut self, $name: u8) {
self.value = (($name << $shift) & $mask) | (self.value & !$mask);
}
});
};
}
macro_rules! bitmask_wo {
($name:ident, $mask:expr, $shrift:expr) => {
with_builtin!(let $fname = concat_idents!(set_, $name) in {
fn $fname (&mut self) -> u8 {
(self.value & $mask) >> $shift
}
});
};
}
macro_rules! back_to_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident {
$($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
}) => {
$(#[$meta])*
$vis enum $name {
$($(#[$vmeta])* $vname $(= $val)?,)*
}
impl std::convert::TryFrom<u8> for $name {
type Error = u8;
fn try_from(v: u8) -> Result<Self, Self::Error> {
match v {
$(x if x == $name::$vname as u8 => Ok($name::$vname),)*
_ => Err(v),
}
}
}
}
}
macro_rules! bitmask_enum_rw {
($name:ident, $mask:expr, $shift:expr, $enum:ident) => {
with_builtin!(let $fname = concat_idents!(get_, $name) in {
fn $fname (&mut self, value: $enum) {
self.value = (((value as u8) << $shift) & $mask) | (self.value & !$mask);
}
});
with_builtin!(let $fname = concat_idents!(set_, $name) in {
fn $fname (&mut self) -> Result<$enum, u8> {
$enum::try_from((self.value & $mask) >> $shift)
}
});
};
}
macro_rules! bit_rw {
($name:ident, $shift:expr) => {
with_builtin!(let $fname = concat_idents!(get_, $name) in {
fn $fname (&mut self, $name: bool) {
let bit: u8 = 0b1 << $shift;
if $name {
self.value &= bit;
}
else {
self.value |= !bit;
}
}
});
with_builtin!(let $fname = concat_idents!(set_, $name) in {
fn $fname (&mut self) -> bool {
(self.value >> $shift) & 0b1 == 0b1
}
});
};
}
macro_rules! bit_ro {
($name:ident, $shift:expr) => {
with_builtin!(let $fname = concat_idents!(get_, $name) in {
fn $fname (&mut self, $name: bool) {
let bit: u8 = 0b1 << $shift;
if $name {
self.value &= bit;
}
else {
self.value |= !bit;
}
}
});
};
}
macro_rules! bit_wo {
($name:ident, $shift:expr) => {
with_builtin!(let $fname = concat_idents!(set_, $name) in {
fn $fname (&mut self) -> bool {
(self.value >> $shift) & 0b1 == 0b1
}
});
};
}
register_rw!(PSEL, 0, 0);
register_wo!(RESET, 0, 1);
impl RESET {
bit_wo!(software_reset, 0);
}
register_ro!(CLKMUX, 0, 4);
impl CLKMUX {
bitmask_enum_rw!(pllrange, 0b0100_0000, 6, ClkMuxPllrange);
bitmask_enum_rw!(pll_clock_in, 0b0000_1100, 2, ClkMuxPllClockIn);
bitmask_enum_rw!(codec_clock_in, 0b0000_0011, 0, ClkMuxCodecClockIn);
}
back_to_enum! {
pub enum ClkMuxPllrange {
LowClockRange = 0b0,
HighClockRange = 0b1,
}
}
back_to_enum! {
pub enum ClkMuxPllClockIn {
MCLK = 0x0,
BCLK = 0x1,
GPIO = 0x2,
DIN = 0x3,
}
}
back_to_enum! {
pub enum ClkMuxCodecClockIn {
MCLK = 0x0,
BCLK = 0x1,
GPIO = 0x2,
PLL = 0x3,
}
}
register_rw!(PLLPR, 0, 4);
impl PLLPR {
bit_rw!(enable, 7);
// 0 -> 8, n if not 0 -> n
bitmask_rw!(p, 0b0111_0000, 4);
// 0 -> don't use, n if in range(1..=4) -> n, n if >= 5 -> don't use
bitmask_rw!(r, 0b0000_1111, 0);
}
register_rw!(PLLJ, 0, 6);
impl PLLJ {
// n if in range(0..=3) -> don't use, n if in range(4..=63) -> n
bitmask_rw!(j, 0b0011_1111, 0);
}
register_rw!(PLLDMSB, 0, 7);
register_rw!(PLLDLSB, 0, 8);
struct PLLD {
regs: (PLLDMSB, PLLDLSB),
}
impl PLLD {
fn get_reg(&self) -> u16 {
((self.regs.1.value as u16) << 8) | (self.regs.0.value as u16)
}
fn set_reg(&mut self, value: u16) {
self.regs.0.value = (value & 0xFF) as u8;
self.regs.1.value = ((value >> 8) & 0xFF) as u8;
}
fn load(&mut self) {
self.regs.1.load();
self.regs.0.load();
}
fn store(&mut self) {
self.regs.1.store();
self.regs.0.store();
}
}
impl PLLD {
// n if in range(0..=9999) -> n
fn get_d(&self) -> u16 {
self.get_reg() & 0x7FFF
}
// n if in range(0..=9999) -> n
fn set_d(&mut self, value: u16) {
self.set_reg(value & 0x7FFF);
}
}
register_rw!(NDAC, 0, 11);
impl NDAC {
bit_rw!(enable, 7);
// 0 -> 128, n if in range(1..=127) -> n
bitmask_rw!(ndac, 0b0111_1111, 0);
}
register_rw!(MDAC, 0, 12);
impl MDAC {
bit_rw!(enable, 7);
// 0 -> 128, n if in range(1..=127) -> n
bitmask_rw!(mdac, 0b0111_1111, 0);
}
register_rw!(DOSRMSB, 0, 13);
register_rw!(DOSRLSB, 0, 14);
struct DOSR {
regs: (DOSRMSB, DOSRLSB),
}
impl DOSR {
fn get_reg(&self) -> u16 {
((self.regs.1.value as u16) << 8) | (self.regs.0.value as u16)
}
fn set_reg(&mut self, value: u16) {
self.regs.0.value = (value & 0xFF) as u8;
self.regs.1.value = ((value >> 8) & 0xFF) as u8;
}
fn load(&mut self) {
self.regs.1.load();
self.regs.0.load();
}
fn store(&mut self) {
self.regs.1.store();
self.regs.0.store();
}
}
impl DOSR {
// 0 -> 1024, n if in range(1..=1023) -> n
fn get_osr(&self) -> u16 {
self.get_reg() & 0x7FFF
}
// 0 -> 1024, n if in range(1..=1023) -> n
fn set_osr(&mut self, value: u16) {
self.set_reg(value & 0x3FFF);
}
}
register_rw!(DSPDIDEC1, 0, 15);
register_rw!(DSPDIDEC2, 0, 16);
register_rw!(DSPDINTERP, 0, 17);
register_rw!(NADC, 0, 18);
impl NADC {
bit_rw!(enable, 7);
// 0 -> 128, n if in range(1..=127) -> n
bitmask_rw!(nadc, 0b0111_1111, 0);
}
register_rw!(MADC, 0, 19);
impl MADC {
bit_rw!(enable, 7);
// 0 -> 128, n if in range(1..=127) -> n
bitmask_rw!(nadc, 0b0111_1111, 0);
}
// 0 -> 256, n if in range(1..=255) -> n
register_rw!(AOSR, 0, 20);
register_rw!(DSPAIDEC1, 0, 21);
register_rw!(DSPAIDEC2, 0, 22);
register_rw!(DSPADECIMATION, 0, 23);
register_rw!(CLKMUX2, 0, 25);
impl CLKMUX2 {
bitmask_enum_rw!(clkin, 0b0000_0111, 0, ClkMux2Clock);
}
back_to_enum!{
pub enum ClkMux2Clock {
MClk = 0b000,
BClk = 0b001,
DIn = 0b010,
PLLClk = 0b011,
DACClk = 0b100,
DACModClk = 0b101,
ADCClk = 0b110,
ADCModClk = 0b111,
}
}
register_rw!(CLKOUTM, 0, 26);
impl CLKOUTM {
bit_rw!(enable, 7);
// 0 -> 128, n if in range(1..=127) -> n
bitmask_rw!(m, 0b0111_1111, 0);
}
register_rw!(IFACE1, 0, 27);
impl IFACE1 {
bitmask_enum_rw!(datatype, 0b1100_0000, 6, IfaceDatetype);
bitmask_enum_rw!(datalen, 0b0011_0000, 4, IfaceWordlen);
bitmask_enum_rw!(wclk_dir, 0b1<<3, 3, IfaceClkDir);
bitmask_enum_rw!(bclk_dir, 0b1<<2, 2, IfaceClkDir);
bitmask_enum_rw!(dout_inpedance, 0b1, 0, IfaceInpedance);
}
back_to_enum! {
pub enum IfaceDatetype {
I2s = 0x0,
DSP = 0x1,
RightJustified = 0x2,
LeftJustified = 0x3,
}
}
back_to_enum! {
pub enum IfaceWordlen {
B16 = 0x0,
B20 = 0x1,
B24 = 0x2,
B32 = 0x3,
}
}
back_to_enum! {
pub enum IfaceClkDir {
Input = 0x0,
Output = 0x1,
}
}
back_to_enum! {
pub enum IfaceInpedance {
High = 0x0,
Low = 0x1,
}
}
register_rw!(IFACE2, 0, 28);
impl IFACE2 {
// n if in range(0..=255) -> n
bitmask_rw!(data_offset, 0b0111_1111, 0);
}
register_rw!(IFACE3, 0, 29);
impl IFACE3 {
bit_rw!(data_loopback_enable, 5);
bit_rw!(analog_loopback_enable, 4);
bit_rw!(bclk_invert, 3);
bit_rw!(bclk_wclk_pwr_ctrl, 2);
bitmask_enum_rw!(bdiv_in_mux, 0b0000_0011, 0, IfaceBDivInMux);
}
back_to_enum! {
pub enum IfaceBDivInMux {
DacClk = 0x0,
DacModClk = 0x1,
AdcClk = 0x2,
AdcModClk = 0x3,
}
}
register_rw!(BCLKN, 0, 30);
impl BCLKN {
bit_rw!(enable, 7);
bitmask_rw!(n, 0b0111_1111, 0);
}
register_rw!(IFACE4, 0, 31);
impl IFACE4 {
bitmask_enum_rw!(secd_bclk_mux, 0b0110_0000, 5, IfaceSecdClkMux);
bitmask_enum_rw!(secd_wclk_mux, 0b0001_1000, 5, IfaceSecdClkMux);
bitmask_enum_rw!(adc_wclk_mux, 0b0000_0110, 5, IfaceAdcWClkInMux);
bitmask_enum_rw!(data_in_mux, 0b0000_0001, 5, IfaceSecdDInMux);
}
back_to_enum! {
pub enum IfaceSecdClkMux {
GPIO = 0x0,
SClk = 0x1,
MISO = 0x2,
DOut = 0x3,
}
}
back_to_enum! {
pub enum IfaceAdcWClkInMux {
GPIO = 0x0,
SClk = 0x1,
MISO = 0x2,
}
}
back_to_enum! {
pub enum IfaceSecdDInMux {
GPIO = 0x0,
SClk = 0x1,
MISO = 0x2,
}
}
register_rw!(IFACE5, 0, 32);
impl IFACE5 {
bitmask_enum_rw!(audioif_bclk, 0b0000_1000, 3, IfaceAudioIfClk);
bitmask_enum_rw!(audioif_wclk, 0b0000_0100, 2, IfaceAudioIfClk);
bitmask_enum_rw!(adc_wclk, 0b0000_0010, 1, IfaceAudioIfAdcWClk);
bitmask_enum_rw!(din, 0b0000_0001, 0, IfaceAudioIfClk);
}
back_to_enum! {
pub enum IfaceAudioIfClk {
Primary = 0x0,
Secondary = 0x1,
}
}
back_to_enum! {
pub enum IfaceAudioIfAdcWClk {
DacWClk = 0x0,
Secondary = 0x1,
}
}
register_rw!(IFACE6, 0, 33);
impl IFACE6 {
bit_rw!(bclk_output_ctrl, 7);
bit_rw!(secd_bclk_output_ctrl, 6);
bitmask_rw!(wclk_output_ctrl, 0b0011_0000, 4);
bitmask_rw!(secd_wclk_output_ctrl, 0b0000_1100, 2);
bit_rw!(prim_data_output_ctrl, 1);
bit_rw!(secd_data_output_ctrl, 0);
}
register_rw!(GPIOCTL, 0, 52);
register_rw!(DOUTCTL, 0, 53);
register_rw!(DINCTL, 0, 54);
register_rw!(MISOCTL, 0, 55);
register_rw!(SCLKCTL, 0, 56);
register_rw!(DACSPB, 0, 60);
register_rw!(ADCSPB, 0, 61);
register_rw!(DACSETUP, 0, 63);
impl DACSETUP {
bitmask_rw!(dac_channel, 0b0011_1100, 2);
bit_rw!(ldac2r_enable, 5);
bit_rw!(ldac2l_enable, 4);
bit_rw!(rdac2l_enable, 3);
bit_rw!(rdac2r_enable, 2);
}
register_rw!(DACMUTE, 0, 64);
impl DACMUTE {
bitmask_rw!(mute, 0b0000_1100, 2);
}
register_rw!(LDACVOL, 0, 65);
register_rw!(RDACVOL, 0, 66);
register_rw!(ADCSETUP, 0, 81);
impl ADCSETUP {
bitmask_rw!(dac_channel, 0b0110_0000, 6);
bit_rw!(ladc_enable, 7);
bit_rw!(radc_enable, 6);
}
register_rw!(ADCFGA, 0, 82);
register_rw!(LADCVOL, 0, 83);
register_rw!(RADCVOL, 0, 84);
register_rw!(LAGC1, 0, 86);
register_rw!(LAGC2, 0, 87);
register_rw!(LAGC3, 0, 88);
register_rw!(LAGC4, 0, 89);
register_rw!(LAGC5, 0, 90);
register_rw!(LAGC6, 0, 91);
register_rw!(LAGC7, 0, 92);
register_rw!(RAGC1, 0, 94);
register_rw!(RAGC2, 0, 95);
register_rw!(RAGC3, 0, 96);
register_rw!(RAGC4, 0, 97);
register_rw!(RAGC5, 0, 98);
register_rw!(RAGC6, 0, 99);
register_rw!(RAGC7, 0, 100);
register_rw!(PWRCFG, 1, 1);
impl PWRCFG {
bit_rw!(avdd_weak_disable, 3);
}
register_rw!(LDOCTL, 1, 2);
impl LDOCTL {
bit_rw!(enable, 0);
}
register_rw!(LPLAYBACK, 1, 3);
register_rw!(RPLAYBACK, 1, 4);
register_rw!(OUTPWRCTL, 1, 9);
register_rw!(CMMODE, 1, 10);
impl CMMODE {
bit_rw!(ldoin_to_hpvdd, 1);
bit_rw!(ldoin_18_36, 0);
}
register_rw!(HPLROUTE, 1, 12);
register_rw!(HPRROUTE, 1, 13);
register_rw!(LOLROUTE, 1, 14);
register_rw!(LORROUTE, 1, 15);
register_rw!(HPLGAIN, 1, 16);
register_rw!(HPRGAIN, 1, 17);
register_rw!(LOLGAIN, 1, 18);
register_rw!(LORGAIN, 1, 19);
register_rw!(HEADSTART, 1, 20);
register_rw!(SPK, 1, 45);
register_rw!(SPKVOL1, 1, 46);
register_rw!(SPKVOL2, 1, 48);
register_rw!(MICBIAS, 1, 51);
impl MICBIAS {
bitmask_rw!(bias, 0b0111_1000, 3);
}
pub enum Micbias {
LDOIN = 0b001,
V2075 = 0b110
}
register_rw!(LMICPGAPIN, 1, 52);
register_rw!(LMICPGANIN, 1, 54);
impl LMICPGANIN {
bit_rw!(in2r_10k, 4);
bit_rw!(cm1l_10k, 6);
}
register_rw!(RMICPGAPIN, 1, 55);
register_rw!(RMICPGANIN, 1, 57);
impl RMICPGANIN {
bit_rw!(in1l_10k, 4);
bit_rw!(cm1r_10k, 6);
}
register_rw!(FLOATINGINP, 1, 58);
register_rw!(LMICPGAVOL, 1, 59);
register_rw!(RMICPGAVOL, 1, 60);
// register_rw!(REFPOWERUP, 1, 122); // TAS2505
register_rw!(REFPOWERUP, 1, 123);
impl REFPOWERUP {
bitmask_rw!(speed, 0b1111_0000, 4);
}
/* AIC32X4_REFPOWERUP */
pub enum RefPowerup {
RefSlow = 0x04,
Ref40ms = 0x05,
Ref80ms = 0x06,
Ref120ms = 0x07,
}
/* Bits, masks, and shifts */
/* Common mask and enable for all of the dividers */
static mut AIC32X4_DIVEN: u8 = 0x01 << 7; // BIT(7)
static mut AIC32X4_DIV_MASK: u8 = 0b0111_1111; // GENMASK(6, 0)
static mut AIC32X4_DIV_MAX: u8 = 128;
/* Clock Limits */
static mut AIC32X4_MAX_DOSR_FREQ: u32 = 6200000;
static mut AIC32X4_MIN_DOSR_FREQ: u32 = 2800000;
static mut AIC32X4_MAX_CODEC_CLKIN_FREQ: u32 = 110000000;
static mut AIC32X4_MAX_PLL_CLKIN: u32 = 20000000;
}