1
//! Clock tree node implementations for the I2S peripherals.
2
//!
3
//! The I2S driver is available only with the `unstable` feature, but the clock tree contains the
4
//! I2S nodes in every build. `lib.rs` therefore includes this module directly, instead of through
5
//! `i2s/mod.rs`.
6
//!
7
//! Each version module implements the nodes of one register layout:
8
//!
9
//! - `v1`: a single `MCLK` node in the I2S register block, shared by both directions.
10
//! - `v2v3`: separate `TX_CLK` and `RX_CLK` nodes, and the `MCLK_OUT` selector, in the I2S register
11
//!   block.
12
//! - `v2v3_pcr`: the same nodes, in the PCR register block.
13
//! - `esp32p4`: the same nodes, in the HP_SYS_CLKRST register block.
14
//! - `v2v3_esp32s31`: the same nodes, in the HP_SYS_CLKRST register block, but with a per-instance
15
//!   register layout.
16

            
17
#[cfg_attr(i2s_version = "1", path = "v1.rs")]
18
#[cfg_attr(i2s_clock_configured_by_pcr, path = "v2v3_pcr.rs")]
19
#[cfg_attr(
20
    all(i2s_clock_configured_by_hp_sys_clkrst, esp32p4),
21
    path = "esp32p4.rs"
22
)]
23
#[cfg_attr(
24
    all(i2s_clock_configured_by_hp_sys_clkrst, esp32s31),
25
    path = "esp32s31.rs"
26
)]
27
#[cfg_attr(
28
    all(
29
        not(i2s_version = "1"),
30
        not(i2s_clock_configured_by_pcr),
31
        not(i2s_clock_configured_by_hp_sys_clkrst)
32
    ),
33
    path = "v2v3.rs"
34
)]
35
mod version;
36

            
37
/// The fractional part of an MCLK divider, in the X/Y/Z/YN1 encoding of the hardware.
38
///
39
/// The clock tree describes the divider as `div_num + div_b / div_a`. This type converts the
40
/// `div_b / div_a` fraction, as `i2s_ll_tx_set_mclk` does in ESP-IDF.
41
#[cfg(not(i2s_version = "1"))]
42
struct MclkFraction {
43
    x: u16,
44
    y: u16,
45
    z: u16,
46
    yn1: bool,
47
}
48

            
49
#[cfg(not(i2s_version = "1"))]
50
impl MclkFraction {
51
    fn new(div_a: u32, div_b: u32) -> Self {
52
25
        let (x, y, z, yn1) = if div_a == 0 || div_b == 0 {
53
            // The divider is an integer one. All coefficients are zero, YN1 included.
54
            (0, 0, 0, false)
55
25
        } else if div_b > div_a / 2 {
56
            // Fractions over one half are encoded as the complement.
57
1
            let z = div_a - div_b;
58
1
            (div_a / z - 1, div_a % z, z, true)
59
        } else {
60
24
            (div_a / div_b - 1, div_a % div_b, div_b, false)
61
        };
62

            
63
        Self {
64
            x: x as u16,
65
            y: y as u16,
66
            z: z as u16,
67
            yn1,
68
        }
69
    }
70
}