use crate::driver::config::{PhyInterface, RmiiClockMode};
use crate::driver::error::{ConfigError, Result};
use crate::internal::register::ext::ExtRegs;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ClockState {
#[default]
Unconfigured,
Enabled,
Disabled,
}
#[derive(Debug)]
pub struct ClockController {
state: ClockState,
interface: PhyInterface,
}
impl ClockController {
pub const fn new() -> Self {
Self {
state: ClockState::Unconfigured,
interface: PhyInterface::Rmii,
}
}
pub fn configure(&mut self, interface: PhyInterface, rmii_clock: RmiiClockMode) -> Result<()> {
self.interface = interface;
match interface {
PhyInterface::Rmii => self.configure_rmii(rmii_clock),
PhyInterface::Mii => self.configure_mii(),
}
}
fn configure_rmii(&mut self, clock_mode: RmiiClockMode) -> Result<()> {
ExtRegs::set_rmii_mode();
match clock_mode {
RmiiClockMode::ExternalInput { gpio } => {
if gpio != 0 {
#[cfg(feature = "esp32")]
return Err(ConfigError::InvalidConfig.into());
}
ExtRegs::configure_gpio0_rmii_clock_input();
ExtRegs::set_rmii_clock_external();
}
RmiiClockMode::InternalOutput { gpio } => {
#[cfg(feature = "esp32")]
if gpio != 0 && gpio != 16 && gpio != 17 {
return Err(ConfigError::InvalidConfig.into());
}
ExtRegs::set_rmii_clock_internal();
}
}
Ok(())
}
fn configure_mii(&mut self) -> Result<()> {
ExtRegs::set_mii_mode();
Ok(())
}
pub fn enable(&mut self) {
ExtRegs::enable_clocks();
ExtRegs::power_up_ram();
self.state = ClockState::Enabled;
}
pub fn disable(&mut self) {
ExtRegs::disable_clocks();
self.state = ClockState::Disabled;
}
pub fn is_enabled(&self) -> bool {
self.state == ClockState::Enabled
}
pub fn state(&self) -> ClockState {
self.state
}
#[allow(unused_variables)]
pub fn set_clock_inversion(&self, invert: bool) {
#[cfg(feature = "defmt")]
if invert {
defmt::warn!("Clock inversion requested but not available on ESP32 EMAC");
}
}
pub fn read_clock_control(&self) -> u32 {
ExtRegs::clk_ctrl()
}
pub fn read_phy_interface_config(&self) -> u32 {
ExtRegs::phy_inf_conf()
}
}
impl Default for ClockController {
fn default() -> Self {
Self::new()
}
}