//! # Radio clocks driver (ESP32) //! //! ## Overview //! //! The `Radio Clocks` module provides control and configuration functions for //! various radio peripherals, such as `PHY`, `Bluetooth (BT)`, and `Wi-Fi`. The //! module allows enabling and disabling these peripherals, resetting the `Media //! Access Control (MAC)` and initializing clocks. //! //! The module defines a `RadioClockController` trait implemented by the //! `RadioClockControl` struct. This trait provides methods to enable, disable, //! reset the MAC, initialize clocks and perform other related operations. use crate::system::{RadioClockControl, RadioClockController, RadioPeripherals}; const DPORT_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x000003c9; const DPORT_WIFI_CLK_WIFI_EN_M: u32 = 0x00000406; const DPORT_WIFI_CLK_BT_EN_M: u32 = 0x00030800; impl RadioClockController for RadioClockControl { fn enable(&mut self, peripheral: RadioPeripherals) { match peripheral { RadioPeripherals::Phy => enable_phy(), RadioPeripherals::Bt => bt_clock_enable(), RadioPeripherals::Wifi => wifi_clock_enable(), } } fn disable(&mut self, peripheral: RadioPeripherals) { match peripheral { RadioPeripherals::Phy => disable_phy(), RadioPeripherals::Bt => bt_clock_disable(), RadioPeripherals::Wifi => wifi_clock_disable(), } } fn reset_mac(&mut self) { reset_mac(); } fn init_clocks(&mut self) { init_clocks(); } fn ble_rtc_clk_init(&mut self) { // nothing for this target } fn reset_rpa(&mut self) { // nothing for this target } } fn enable_phy() { // `periph_ll_wifi_bt_module_enable_clk_clear_rst` let dport = unsafe { &*esp32::DPORT::PTR }; dport .wifi_clk_en .modify(|r, w| unsafe { w.bits(r.bits() | DPORT_WIFI_CLK_WIFI_BT_COMMON_M) }); } fn disable_phy() { // `periph_ll_wifi_bt_module_disable_clk_set_rst` let dport = unsafe { &*esp32::DPORT::PTR }; dport .wifi_clk_en .modify(|r, w| unsafe { w.bits(r.bits() & !DPORT_WIFI_CLK_WIFI_BT_COMMON_M) }); } fn bt_clock_enable() { let dport = unsafe { &*esp32::DPORT::PTR }; dport .wifi_clk_en .modify(|r, w| unsafe { w.bits(r.bits() | DPORT_WIFI_CLK_BT_EN_M) }); } fn bt_clock_disable() { let dport = unsafe { &*esp32::DPORT::PTR }; dport .wifi_clk_en .modify(|r, w| unsafe { w.bits(r.bits() & !DPORT_WIFI_CLK_BT_EN_M) }); } fn wifi_clock_enable() { // `periph_ll_wifi_module_enable_clk_clear_rst` let dport = unsafe { &*esp32::DPORT::PTR }; dport .wifi_clk_en .modify(|r, w| unsafe { w.bits(r.bits() | DPORT_WIFI_CLK_WIFI_EN_M) }); } fn wifi_clock_disable() { // `periph_ll_wifi_module_disable_clk_set_rst` let dport = unsafe { &*esp32::DPORT::PTR }; dport .wifi_clk_en .modify(|r, w| unsafe { w.bits(r.bits() & !DPORT_WIFI_CLK_WIFI_EN_M) }); } fn reset_mac() { const SYSTEM_MAC_RST: u8 = 1 << 2; let dport = unsafe { &*esp32::DPORT::PTR }; dport .core_rst_en .modify(|r, w| unsafe { w.core_rst().bits(r.core_rst().bits() | SYSTEM_MAC_RST) }); dport .core_rst_en .modify(|r, w| unsafe { w.core_rst().bits(r.core_rst().bits() & !SYSTEM_MAC_RST) }); } fn init_clocks() { let dport = unsafe { &*esp32::DPORT::PTR }; // esp-idf assumes all clocks are enabled by default, and disables the following // bits: // // ``` // const DPORT_WIFI_CLK_SDIOSLAVE_EN: u32 = 1 << 4; // const DPORT_WIFI_CLK_UNUSED_BIT5: u32 = 1 << 5; // const DPORT_WIFI_CLK_UNUSED_BIT12: u32 = 1 << 12; // const DPORT_WIFI_CLK_SDIO_HOST_EN: u32 = 1 << 13; // const DPORT_WIFI_CLK_EMAC_EN: u32 = 1 << 14; // // const WIFI_BT_SDIO_CLK: u32 = DPORT_WIFI_CLK_WIFI_EN_M // | DPORT_WIFI_CLK_BT_EN_M // | DPORT_WIFI_CLK_UNUSED_BIT5 // | DPORT_WIFI_CLK_UNUSED_BIT12 // | DPORT_WIFI_CLK_SDIOSLAVE_EN // | DPORT_WIFI_CLK_SDIO_HOST_EN // | DPORT_WIFI_CLK_EMAC_EN; // ``` // // However, we can't do this because somehow our initialization process is // different, and disabling some bits, or not enabling them makes the BT // stack crash. dport.wifi_clk_en.write(|w| unsafe { w.bits(u32::MAX) }); }