use core::marker::PhantomData;
use esp_idf_sys::*;
pub mod config {
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct LdoChannelConfig {
pub voltage_mv: i32,
pub owned_by_hw: bool,
}
impl LdoChannelConfig {
pub const fn new(voltage_mv: i32) -> Self {
Self {
voltage_mv,
owned_by_hw: false,
}
}
#[must_use]
pub fn voltage_mv(mut self, voltage_mv: i32) -> Self {
self.voltage_mv = voltage_mv;
self
}
#[must_use]
pub fn owned_by_hw(mut self, owned_by_hw: bool) -> Self {
self.owned_by_hw = owned_by_hw;
self
}
}
}
pub trait VoltageType {
const IS_ADJUSTABLE: bool;
}
pub struct Adjustable;
pub struct Fixed;
impl VoltageType for Adjustable {
const IS_ADJUSTABLE: bool = true;
}
impl VoltageType for Fixed {
const IS_ADJUSTABLE: bool = false;
}
pub struct LdoChannel<'d, V: VoltageType> {
handle: esp_ldo_channel_handle_t,
_p: PhantomData<&'d mut ()>,
_v: PhantomData<V>,
}
impl<'d, V: VoltageType> LdoChannel<'d, V> {
#[allow(clippy::needless_update)]
pub fn new<LDO: Ldo<VoltageType = V> + 'd>(
_ldo: LDO,
config: &config::LdoChannelConfig,
) -> Result<LdoChannel<'d, V>, EspError> {
let ldo_config = esp_ldo_channel_config_t {
chan_id: LDO::channel(),
voltage_mv: config.voltage_mv,
flags: esp_ldo_channel_config_t_ldo_extra_flags {
_bitfield_1: esp_ldo_channel_config_t_ldo_extra_flags::new_bitfield_1(
V::IS_ADJUSTABLE as u32,
config.owned_by_hw as u32,
0, ),
..Default::default()
},
..Default::default()
};
let mut handle: esp_ldo_channel_handle_t = core::ptr::null_mut();
esp!(unsafe { esp_ldo_acquire_channel(&ldo_config, &mut handle) })?;
if handle.is_null() {
return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
}
Ok(LdoChannel {
handle,
_p: PhantomData,
_v: PhantomData,
})
}
pub fn handle(&self) -> esp_ldo_channel_handle_t {
self.handle
}
}
impl<'d> LdoChannel<'d, Adjustable> {
pub fn adjust_voltage(&mut self, voltage_mv: i32) -> Result<(), EspError> {
esp!(unsafe { esp_ldo_channel_adjust_voltage(self.handle, voltage_mv) })?;
Ok(())
}
}
impl<'d, V: VoltageType> Drop for LdoChannel<'d, V> {
fn drop(&mut self) {
if !self.handle.is_null() {
let _ = esp!(unsafe { esp_ldo_release_channel(self.handle) });
}
}
}
unsafe impl<'d, V: VoltageType> Send for LdoChannel<'d, V> {}
pub use config::*;
pub trait Ldo {
type VoltageType: VoltageType;
fn channel() -> i32;
}
macro_rules! impl_ldo {
($ldo:ident: $channel:expr) => {
pub struct $ldo<'a, V: VoltageType>(
::core::marker::PhantomData<&'a mut ()>,
::core::marker::PhantomData<V>,
);
impl<'a, V: VoltageType> $ldo<'a, V> {
#[inline(always)]
pub unsafe fn steal() -> Self {
Self(::core::marker::PhantomData, ::core::marker::PhantomData)
}
#[inline]
#[allow(dead_code)]
pub unsafe fn reborrow(&mut self) -> $ldo<'_, V> {
Self(::core::marker::PhantomData, ::core::marker::PhantomData)
}
}
unsafe impl<'a, V: VoltageType> Send for $ldo<'a, V> {}
impl<'a, V: VoltageType> Ldo for $ldo<'a, V> {
type VoltageType = V;
#[inline(always)]
fn channel() -> i32 {
$channel
}
}
};
}
#[cfg(esp32p4)]
impl_ldo!(LDO1: 1);
#[cfg(esp32p4)]
impl_ldo!(LDO2: 2);
#[cfg(esp32p4)]
impl_ldo!(LDO3: 3);
#[cfg(esp32p4)]
impl_ldo!(LDO4: 4);