teensy4_bsp/
clock_power.rs1#![allow(clippy::assertions_on_constants)]
4
5use crate::{
6 hal::{
7 self,
8 ccm::{self, clock_gate, XTAL_OSCILLATOR_HZ},
9 dcdc,
10 },
11 ral,
12};
13
14pub use hal::lpi2c::ClockSpeed as Lpi2cClockSpeed;
15
16pub const XTAL_OSCILLATOR_FREQUENCY: u32 = XTAL_OSCILLATOR_HZ;
20
21const PLL1_DIV_SEL: u32 = 100;
22const ARM_DIVIDER: u32 = 2;
23const AHB_DIVIDER: u32 = 1;
24const IPG_DIVIDER: u32 = 4;
25
26pub const ARM_FREQUENCY: u32 =
31 ccm::analog::pll1::frequency(PLL1_DIV_SEL) / ARM_DIVIDER / AHB_DIVIDER;
32const _: () = assert!(ARM_FREQUENCY == 600_000_000);
33
34pub const IPG_FREQUENCY: u32 = ARM_FREQUENCY / IPG_DIVIDER;
36const _: () = assert!(IPG_FREQUENCY == 150_000_000);
37
38fn setup_ahb_ipg_clk(ccm: &mut ral::ccm::CCM, ccm_analog: &mut ral::ccm_analog::CCM_ANALOG) {
40 clock_gate::IPG_CLOCK_GATES
41 .iter()
42 .for_each(|locator| locator.set(ccm, clock_gate::OFF));
43
44 if ccm::ahb_clk::Selection::PeriphClk2Sel == ccm::ahb_clk::selection(ccm) {
45 ccm::ahb_clk::set_selection(ccm, ccm::ahb_clk::Selection::PrePeriphClkSel);
48 }
49
50 ccm::periph_clk2::set_divider(ccm, 1);
52 ccm::periph_clk2::set_selection(ccm, ccm::periph_clk2::Selection::Osc);
53 ccm::ahb_clk::set_selection(ccm, ccm::ahb_clk::Selection::PeriphClk2Sel);
54
55 ccm::analog::pll1::restart(ccm_analog, PLL1_DIV_SEL);
57 ccm::arm_divider::set_divider(ccm, ARM_DIVIDER);
58 ccm::ahb_clk::set_divider(ccm, AHB_DIVIDER);
59
60 ccm::pre_periph_clk::set_selection(ccm, ccm::pre_periph_clk::Selection::Pll1);
62 ccm::ahb_clk::set_selection(ccm, ccm::ahb_clk::Selection::PrePeriphClkSel);
63
64 ccm::ipg_clk::set_divider(ccm, IPG_DIVIDER);
65}
66
67const PERCLK_DIVIDER: u32 = 24;
68pub const PERCLK_FREQUENCY: u32 = XTAL_OSCILLATOR_FREQUENCY / PERCLK_DIVIDER;
76const _: () = assert!(PERCLK_FREQUENCY == 1_000_000);
77
78fn setup_perclk_clk(ccm: &mut ral::ccm::CCM) {
80 clock_gate::PERCLK_CLOCK_GATES
81 .iter()
82 .for_each(|locator| locator.set(ccm, clock_gate::OFF));
83 ccm::perclk_clk::set_divider(ccm, PERCLK_DIVIDER);
84 ccm::perclk_clk::set_selection(ccm, ccm::perclk_clk::Selection::Oscillator);
85}
86
87const UART_DIVIDER: u32 = 3;
88pub const UART_FREQUENCY: u32 = XTAL_OSCILLATOR_FREQUENCY / UART_DIVIDER;
93
94fn setup_uart_clk(ccm: &mut ral::ccm::CCM) {
96 clock_gate::UART_CLOCK_GATES
97 .iter()
98 .for_each(|locator| locator.set(ccm, clock_gate::OFF));
99
100 ccm::uart_clk::set_selection(ccm, ccm::uart_clk::Selection::Oscillator);
101 ccm::uart_clk::set_divider(ccm, UART_DIVIDER);
102}
103
104pub type LpuartBaud = hal::lpuart::Baud;
108
109pub const fn lpuart_baud(bps: u32) -> hal::lpuart::Baud {
121 hal::lpuart::Baud::compute(UART_FREQUENCY, bps)
122}
123
124const LPI2C_DIVIDER: u32 = 3;
125const LPI2C_CLOCK_SOURCE: ccm::lpi2c_clk::Selection = ccm::lpi2c_clk::Selection::Oscillator;
126
127pub const LPI2C_FREQUENCY: u32 = XTAL_OSCILLATOR_FREQUENCY / LPI2C_DIVIDER;
129const _: () = assert!(LPI2C_FREQUENCY == 8_000_000);
130
131fn setup_lpi2c_clk(ccm: &mut ral::ccm::CCM) {
133 clock_gate::LPI2C_CLOCK_GATES
134 .iter()
135 .for_each(|locator| locator.set(ccm, clock_gate::OFF));
136 ccm::lpi2c_clk::set_divider(ccm, LPI2C_DIVIDER);
137 ccm::lpi2c_clk::set_selection(ccm, LPI2C_CLOCK_SOURCE);
138}
139
140pub type Lpi2cBaud = hal::lpi2c::Timing;
142
143pub const fn lpi2c_baud(clock_speed: Lpi2cClockSpeed) -> Lpi2cBaud {
159 Lpi2cBaud::ideal(LPI2C_FREQUENCY, clock_speed)
160}
161
162const LPSPI_DIVIDER: u32 = 4;
163pub const LPSPI_FREQUENCY: u32 = ccm::analog::pll2::FREQUENCY / LPSPI_DIVIDER;
165const _: () = assert!(LPSPI_FREQUENCY == 132_000_000);
166
167fn setup_lpspi_clk(ccm: &mut ral::ccm::CCM) {
169 clock_gate::LPSPI_CLOCK_GATES
170 .iter()
171 .for_each(|locator| locator.set(ccm, clock_gate::OFF));
172 ccm::lpspi_clk::set_selection(ccm, ccm::lpspi_clk::Selection::Pll2);
173 ccm::lpspi_clk::set_divider(ccm, LPSPI_DIVIDER);
174}
175
176const CLOCK_GATES: &[clock_gate::Locator] = &[
177 clock_gate::pit(),
178 clock_gate::gpt_bus::<1>(),
179 clock_gate::gpt_bus::<2>(),
180 clock_gate::gpt_serial::<1>(),
181 clock_gate::gpt_serial::<2>(),
182 clock_gate::gpio::<1>(),
183 clock_gate::gpio::<2>(),
184 clock_gate::gpio::<3>(),
185 clock_gate::gpio::<4>(),
186 clock_gate::usb(),
187 clock_gate::dma(),
188 clock_gate::snvs_lp(),
189 clock_gate::snvs_hp(),
190 clock_gate::lpi2c::<1>(),
191 clock_gate::lpi2c::<3>(),
192 clock_gate::lpspi::<1>(),
193 clock_gate::lpspi::<2>(),
194 clock_gate::lpspi::<3>(),
195 clock_gate::lpspi::<4>(),
196 clock_gate::lpuart::<6>(),
197 clock_gate::lpuart::<4>(),
198 clock_gate::lpuart::<2>(),
199 clock_gate::lpuart::<3>(),
200 clock_gate::lpuart::<8>(),
201 clock_gate::lpuart::<1>(),
202 clock_gate::lpuart::<7>(),
203 clock_gate::lpuart::<5>(),
204 clock_gate::flexpwm::<1>(),
205 clock_gate::flexpwm::<2>(),
206 clock_gate::flexpwm::<3>(),
207 clock_gate::flexpwm::<4>(),
208 clock_gate::flexio::<1>(),
209 clock_gate::flexio::<2>(),
210 clock_gate::flexio::<3>(),
211 clock_gate::adc::<1>(),
212 clock_gate::adc::<2>(),
213 clock_gate::trng(),
214];
215
216pub fn prepare_clocks_and_power(
221 ccm: &mut ral::ccm::CCM,
222 ccm_analog: &mut ral::ccm_analog::CCM_ANALOG,
223 dcdc: &mut ral::dcdc::DCDC,
224) {
225 ccm::set_low_power_mode(ccm, ccm::LowPowerMode::RemainInRun);
226 dcdc::set_target_vdd_soc(dcdc, 1250);
227 ccm::analog::pll3::restart(ccm_analog);
228
229 setup_ahb_ipg_clk(ccm, ccm_analog);
230 setup_lpi2c_clk(ccm);
231 setup_lpspi_clk(ccm);
232 setup_perclk_clk(ccm);
233 setup_uart_clk(ccm);
234
235 CLOCK_GATES
236 .iter()
237 .for_each(|locator| locator.set(ccm, clock_gate::ON));
238}