teensy4_bsp/
clock_power.rs#![allow(clippy::assertions_on_constants)]
use crate::{
hal::{
self,
ccm::{self, clock_gate, XTAL_OSCILLATOR_HZ},
dcdc,
},
ral,
};
pub use hal::lpi2c::ClockSpeed as Lpi2cClockSpeed;
pub const XTAL_OSCILLATOR_FREQUENCY: u32 = XTAL_OSCILLATOR_HZ;
const PLL1_DIV_SEL: u32 = 100;
const ARM_DIVIDER: u32 = 2;
const AHB_DIVIDER: u32 = 1;
const IPG_DIVIDER: u32 = 4;
pub const ARM_FREQUENCY: u32 =
ccm::analog::pll1::frequency(PLL1_DIV_SEL) / ARM_DIVIDER / AHB_DIVIDER;
const _: () = assert!(ARM_FREQUENCY == 600_000_000);
pub const IPG_FREQUENCY: u32 = ARM_FREQUENCY / IPG_DIVIDER;
const _: () = assert!(IPG_FREQUENCY == 150_000_000);
fn setup_ahb_ipg_clk(ccm: &mut ral::ccm::CCM, ccm_analog: &mut ral::ccm_analog::CCM_ANALOG) {
clock_gate::IPG_CLOCK_GATES
.iter()
.for_each(|locator| locator.set(ccm, clock_gate::OFF));
if ccm::ahb_clk::Selection::PeriphClk2Sel == ccm::ahb_clk::selection(ccm) {
ccm::ahb_clk::set_selection(ccm, ccm::ahb_clk::Selection::PrePeriphClkSel);
}
ccm::periph_clk2::set_divider(ccm, 1);
ccm::periph_clk2::set_selection(ccm, ccm::periph_clk2::Selection::Osc);
ccm::ahb_clk::set_selection(ccm, ccm::ahb_clk::Selection::PeriphClk2Sel);
ccm::analog::pll1::restart(ccm_analog, PLL1_DIV_SEL);
ccm::arm_divider::set_divider(ccm, ARM_DIVIDER);
ccm::ahb_clk::set_divider(ccm, AHB_DIVIDER);
ccm::pre_periph_clk::set_selection(ccm, ccm::pre_periph_clk::Selection::Pll1);
ccm::ahb_clk::set_selection(ccm, ccm::ahb_clk::Selection::PrePeriphClkSel);
ccm::ipg_clk::set_divider(ccm, IPG_DIVIDER);
}
const PERCLK_DIVIDER: u32 = 24;
pub const PERCLK_FREQUENCY: u32 = XTAL_OSCILLATOR_FREQUENCY / PERCLK_DIVIDER;
const _: () = assert!(PERCLK_FREQUENCY == 1_000_000);
fn setup_perclk_clk(ccm: &mut ral::ccm::CCM) {
clock_gate::PERCLK_CLOCK_GATES
.iter()
.for_each(|locator| locator.set(ccm, clock_gate::OFF));
ccm::perclk_clk::set_divider(ccm, PERCLK_DIVIDER);
ccm::perclk_clk::set_selection(ccm, ccm::perclk_clk::Selection::Oscillator);
}
const UART_DIVIDER: u32 = 3;
pub const UART_FREQUENCY: u32 = XTAL_OSCILLATOR_FREQUENCY / UART_DIVIDER;
fn setup_uart_clk(ccm: &mut ral::ccm::CCM) {
clock_gate::UART_CLOCK_GATES
.iter()
.for_each(|locator| locator.set(ccm, clock_gate::OFF));
ccm::uart_clk::set_selection(ccm, ccm::uart_clk::Selection::Oscillator);
ccm::uart_clk::set_divider(ccm, UART_DIVIDER);
}
pub type LpuartBaud = hal::lpuart::Baud;
pub const fn lpuart_baud(bps: u32) -> hal::lpuart::Baud {
hal::lpuart::Baud::compute(UART_FREQUENCY, bps)
}
const LPI2C_DIVIDER: u32 = 3;
const LPI2C_CLOCK_SOURCE: ccm::lpi2c_clk::Selection = ccm::lpi2c_clk::Selection::Oscillator;
pub const LPI2C_FREQUENCY: u32 = XTAL_OSCILLATOR_FREQUENCY / LPI2C_DIVIDER;
const _: () = assert!(LPI2C_FREQUENCY == 8_000_000);
fn setup_lpi2c_clk(ccm: &mut ral::ccm::CCM) {
clock_gate::LPI2C_CLOCK_GATES
.iter()
.for_each(|locator| locator.set(ccm, clock_gate::OFF));
ccm::lpi2c_clk::set_divider(ccm, LPI2C_DIVIDER);
ccm::lpi2c_clk::set_selection(ccm, LPI2C_CLOCK_SOURCE);
}
pub type Lpi2cBaud = hal::lpi2c::Timing;
pub const fn lpi2c_baud(clock_speed: Lpi2cClockSpeed) -> Lpi2cBaud {
Lpi2cBaud::ideal(LPI2C_FREQUENCY, clock_speed)
}
const LPSPI_DIVIDER: u32 = 4;
pub const LPSPI_FREQUENCY: u32 = ccm::analog::pll2::FREQUENCY / LPSPI_DIVIDER;
const _: () = assert!(LPSPI_FREQUENCY == 132_000_000);
fn setup_lpspi_clk(ccm: &mut ral::ccm::CCM) {
clock_gate::LPSPI_CLOCK_GATES
.iter()
.for_each(|locator| locator.set(ccm, clock_gate::OFF));
ccm::lpspi_clk::set_selection(ccm, ccm::lpspi_clk::Selection::Pll2);
ccm::lpspi_clk::set_divider(ccm, LPSPI_DIVIDER);
}
const CLOCK_GATES: &[clock_gate::Locator] = &[
clock_gate::pit(),
clock_gate::gpt_bus::<1>(),
clock_gate::gpt_bus::<2>(),
clock_gate::gpt_serial::<1>(),
clock_gate::gpt_serial::<2>(),
clock_gate::gpio::<1>(),
clock_gate::gpio::<2>(),
clock_gate::gpio::<3>(),
clock_gate::gpio::<4>(),
clock_gate::usb(),
clock_gate::dma(),
clock_gate::snvs_lp(),
clock_gate::snvs_hp(),
clock_gate::lpi2c::<1>(),
clock_gate::lpi2c::<3>(),
clock_gate::lpspi::<1>(),
clock_gate::lpspi::<2>(),
clock_gate::lpspi::<3>(),
clock_gate::lpspi::<4>(),
clock_gate::lpuart::<6>(),
clock_gate::lpuart::<4>(),
clock_gate::lpuart::<2>(),
clock_gate::lpuart::<3>(),
clock_gate::lpuart::<8>(),
clock_gate::lpuart::<1>(),
clock_gate::flexpwm::<1>(),
clock_gate::flexpwm::<2>(),
clock_gate::flexpwm::<3>(),
clock_gate::flexpwm::<4>(),
clock_gate::flexio::<1>(),
clock_gate::flexio::<2>(),
clock_gate::flexio::<3>(),
clock_gate::adc::<1>(),
clock_gate::adc::<2>(),
clock_gate::trng(),
];
pub fn prepare_clocks_and_power(
ccm: &mut ral::ccm::CCM,
ccm_analog: &mut ral::ccm_analog::CCM_ANALOG,
dcdc: &mut ral::dcdc::DCDC,
) {
ccm::set_low_power_mode(ccm, ccm::LowPowerMode::RemainInRun);
dcdc::set_target_vdd_soc(dcdc, 1250);
ccm::analog::pll3::restart(ccm_analog);
setup_ahb_ipg_clk(ccm, ccm_analog);
setup_lpi2c_clk(ccm);
setup_lpspi_clk(ccm);
setup_perclk_clk(ccm);
setup_uart_clk(ccm);
CLOCK_GATES
.iter()
.for_each(|locator| locator.set(ccm, clock_gate::ON));
}