1use super::{PdmDownsampleRate, PdmError, PdmRxClockConfig, PdmTxClockConfig};
4use crate::{i2s::master::private::I2sClockDividers, soc, time::Rate};
5
6pub(crate) const PDM_BCK_FACTOR: u32 = 64;
7pub(crate) const PDM_TX_BCLK_DIV_MIN: u32 = 8;
8pub(crate) const PDM_RX_BCLK_DIV_MIN: u32 = 8;
9
10pub(crate) struct PdmTxClockResult {
11 pub dividers: I2sClockDividers,
12 pub over_sample_ratio: u32,
13}
14
15pub(crate) struct PdmRxClockResult {
16 pub dividers: I2sClockDividers,
17}
18
19fn calculate_mclk_dividers(sclk: u32, mclk: u32) -> Result<I2sClockDividers, PdmError> {
20 if (sclk as u64) * 100 <= (mclk as u64) * 199 {
22 return Err(PdmError::InvalidClock);
23 }
24
25 let dividers = I2sClockDividers::from_frequencies(sclk, mclk, 0);
26
27 if dividers.mclk_divider >= 256 {
28 return Err(PdmError::InvalidClock);
29 }
30
31 Ok(dividers)
32}
33
34pub(crate) fn calculate_tx_clock(
35 clk: &PdmTxClockConfig,
36 pcm: bool,
37) -> Result<PdmTxClockResult, PdmError> {
38 if clk.up_sample_fs > 480 {
39 return Err(PdmError::InvalidClock);
40 }
41
42 let rate = clk.sample_rate.as_hz();
43 let bclk_div = clk.bclk_div.max(PDM_TX_BCLK_DIV_MIN);
44
45 let (bclk, over_sample_ratio) = if pcm {
46 let over_sample_ratio = clk.up_sample_fp / clk.up_sample_fs.max(1);
47 (rate * PDM_BCK_FACTOR * over_sample_ratio, over_sample_ratio)
48 } else {
49 (rate * 2, 0)
50 };
51
52 let mclk = bclk * bclk_div;
53 let sclk = soc::i2s_sclk_frequency();
54 let mut dividers = calculate_mclk_dividers(sclk, mclk)?;
55 dividers.bclk_divider = bclk_div;
56
57 Ok(PdmTxClockResult {
58 dividers,
59 over_sample_ratio,
60 })
61}
62
63const PDM_RX_CLK_LIMIT_COEFF: u32 = 128;
64
65pub(crate) fn calculate_rx_clock(
66 clk: &PdmRxClockConfig,
67 pcm: bool,
68 slot_mask: u16,
69) -> Result<PdmRxClockResult, PdmError> {
70 let rate = clk.sample_rate.as_hz();
71 let dn_sample_factor = PDM_BCK_FACTOR * clk.downsample_rate.factor();
72 let slot_num = slot_mask.count_ones().max(1);
73
74 let bclk = if pcm {
75 rate * dn_sample_factor
76 } else {
77 rate * 2
78 };
79
80 let bclk_limit = (PDM_RX_CLK_LIMIT_COEFF * slot_num).div_ceil(dn_sample_factor);
81 let bclk_div = clk.bclk_div.max(PDM_RX_BCLK_DIV_MIN).max(bclk_limit);
82
83 let mclk = bclk * bclk_div;
84 let sclk = soc::i2s_sclk_frequency();
85 let mut dividers = calculate_mclk_dividers(sclk, mclk)?;
86 dividers.bclk_divider = bclk_div;
87
88 Ok(PdmRxClockResult { dividers })
89}
90
91impl PdmDownsampleRate {
92 fn factor(self) -> u32 {
93 match self {
94 PdmDownsampleRate::Dsr8s => 1,
95 PdmDownsampleRate::Dsr16s => 2,
96 }
97 }
98}
99
100impl PdmTxClockConfig {
101 pub fn codec_default(sample_rate: Rate) -> Self {
103 Self {
104 sample_rate,
105 up_sample_fp: 960,
106 up_sample_fs: 480,
107 bclk_div: PDM_TX_BCLK_DIV_MIN,
108 }
109 }
110
111 pub fn dac_default(sample_rate: Rate) -> Self {
113 Self {
114 sample_rate,
115 up_sample_fp: 960,
116 up_sample_fs: sample_rate.as_hz() / 100,
117 bclk_div: 13,
118 }
119 }
120}
121
122impl PdmRxClockConfig {
123 pub fn default(sample_rate: Rate) -> Self {
125 Self {
126 sample_rate,
127 downsample_rate: PdmDownsampleRate::Dsr8s,
128 bclk_div: PDM_RX_BCLK_DIV_MIN,
129 }
130 }
131}