diff --git a/rust/kernel/regulator/driver.rs b/rust/kernel/regulator/driver.rs index b8b27d5fdbd7f2..235b45b38b1752 100644 --- a/rust/kernel/regulator/driver.rs +++ b/rust/kernel/regulator/driver.rs @@ -48,14 +48,27 @@ use crate::{ macros::vtable, regulator::Mode, str::CStr, + sync::Arc, types::ForeignOwnable, ThisModule, }; +#[cfg(CONFIG_REGMAP)] +use crate::{error::to_result, regmap::Regmap}; use core::{ marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, }; +#[cfg(not(CONFIG_REGMAP))] +struct Regmap; + +#[cfg(not(CONFIG_REGMAP))] +impl Regmap { + fn as_ptr(&self) -> *mut bindings::regmap { + core::ptr::null_mut() + } +} + /// [`Regulator`]'s status /// /// Corresponds to the kernel's [`enum regulator_status`]. @@ -342,6 +355,7 @@ unsafe impl Sync for Desc {} pub struct Config { cfg: bindings::regulator_config, data: T, + regmap: Option>, } impl Config { @@ -353,8 +367,16 @@ impl Config { ..Default::default() }, data, + regmap: None, } } + + /// Assign a regmap device to the config + #[cfg(CONFIG_REGMAP)] + pub fn with_regmap(mut self, regmap: Arc) -> Self { + self.regmap = Some(regmap); + self + } } /// Registration structure for Regulator drivers. @@ -381,6 +403,7 @@ impl Registration { /// * [`Self`] has ownership of `self.rdev` memory allocation. pub struct Regulator { rdev: *mut bindings::regulator_dev, + _regmap: Option>, } impl Regulator { @@ -392,6 +415,11 @@ impl Regulator { ) -> Result { config.cfg.driver_data = config.data.into_foreign() as _; + let regmap = config.regmap.take(); + if let Some(regmap) = ®map { + config.cfg.regmap = regmap.as_ptr(); + }; + // SAFETY: By the type invariants, we know that `dev.as_ref().as_raw()` is always // valid and non-null, and the descriptor and config are guaranteed to be valid values, // hence it is safe to perform the FFI call. @@ -402,7 +430,10 @@ impl Regulator { if rdev.is_null() { Err(EINVAL) } else { - Ok(Self { rdev }) + Ok(Self { + rdev, + _regmap: regmap, + }) } } @@ -439,9 +470,17 @@ impl Regulator { impl Drop for Regulator { fn drop(&mut self) { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let regmap = unsafe { bindings::rdev_get_regmap(self.rdev) }; + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, // so it is safe to perform the FFI call. unsafe { bindings::regulator_unregister(self.rdev) } + + if !regmap.is_null() { + drop(unsafe { Arc::from_raw(regmap) }); + } } } @@ -449,6 +488,117 @@ impl Drop for Regulator { // implementation. It is safe to use it from any thread. unsafe impl Send for Regulator {} +mod sealed { + pub trait Sealed {} +} + +impl sealed::Sealed for Regulator {} + +/// Helper functions to implement some of the [`Driver`] trait methods using [`Regmap`]. +/// +/// This trait is implemented by [`Regulator`] and is Sealed to prevent +/// to be implemented by anyone else. +#[cfg(CONFIG_REGMAP)] +pub trait RegmapHelpers: sealed::Sealed { + /// Implementation of [`Driver::get_voltage_sel`] using [`Regmap`]. + fn get_voltage_sel_regmap(&self) -> Result; + /// Implementation of [`Driver::set_voltage_sel`] using [`Regmap`]. + fn set_voltage_sel_regmap(&self, sel: u32) -> Result; + + /// Implementation of [`Driver::is_enabled`] using [`Regmap`]. + /// + /// [`Desc::with_enable`] or [`Desc::with_inverted_enable`] must have been called + /// to setup the fields required by regmap. + fn is_enabled_regmap(&self) -> Result; + + /// Implementation of [`Driver::enable`] using [`Regmap`]. + /// + /// [`Desc::with_enable`] or [`Desc::with_inverted_enable`] must have been called + /// to setup the fields required by regmap. + fn enable_regmap(&self) -> Result; + + /// Implementation of [`Driver::disable`] using [`Regmap`]. + /// + /// [`Desc::with_enable`] or [`Desc::with_inverted_enable`] must have been called + /// to setup the fields required by regmap. + fn disable_regmap(&self) -> Result; + + /// Implementation of [`Driver::set_active_discharge`] using [`Regmap`]. + /// + /// [`Desc::with_active_discharge`] must have been called to setup the fields required + /// by regmap. + fn set_active_discharge_regmap(&self, enable: bool) -> Result; + /// Implementation of [`Driver::set_current_limit`] using [`Regmap`]. + fn set_current_limit_regmap(&self, min_ua: i32, max_ua: i32) -> Result; + /// Implementation of [`Driver::get_current_limit`] using [`Regmap`]. + fn get_current_limit_regmap(&self) -> Result; +} + +#[cfg(CONFIG_REGMAP)] +impl RegmapHelpers for Regulator { + fn get_voltage_sel_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let ret = unsafe { bindings::regulator_get_voltage_sel_regmap(self.rdev) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + Ok(ret) + } + + fn set_voltage_sel_regmap(&self, sel: u32) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_set_voltage_sel_regmap(self.rdev, sel) }) + } + + fn is_enabled_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let ret = unsafe { bindings::regulator_is_enabled_regmap(self.rdev) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + Ok(ret > 0) + } + + fn enable_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_enable_regmap(self.rdev) }) + } + + fn disable_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_disable_regmap(self.rdev) }) + } + + fn set_active_discharge_regmap(&self, enable: bool) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { bindings::regulator_set_active_discharge_regmap(self.rdev, enable) }) + } + + fn set_current_limit_regmap(&self, min_ua: i32, max_ua: i32) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + to_result(unsafe { + bindings::regulator_set_current_limit_regmap(self.rdev, min_ua, max_ua) + }) + } + + fn get_current_limit_regmap(&self) -> Result { + // SAFETY: The type invariants guarantee that `self.rdev` is valid and non-null, + // so it is safe to perform the FFI call. + let ret = unsafe { bindings::regulator_get_current_limit_regmap(self.rdev) }; + if ret < 0 { + return Err(Error::from_errno(ret)); + } + Ok(ret) + } +} + /// [`Regulator`] type pub enum Type { /// Voltage regulator @@ -464,7 +614,10 @@ impl Adapter { rdev: *mut bindings::regulator_dev, selector: core::ffi::c_uint, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| T::list_voltage(&rdev, selector)) } @@ -474,7 +627,10 @@ impl Adapter { max_uv: core::ffi::c_int, selector: *mut core::ffi::c_uint, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); match T::set_voltage(&rdev, min_uv, max_uv) { Ok(v) => { unsafe { *selector = v as _ }; @@ -489,7 +645,10 @@ impl Adapter { min_uv: core::ffi::c_int, max_uv: core::ffi::c_int, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| T::map_voltage(&rdev, min_uv, max_uv)) } @@ -497,7 +656,10 @@ impl Adapter { rdev: *mut bindings::regulator_dev, selector: core::ffi::c_uint, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::set_voltage_sel(&rdev, selector)?; Ok(0) @@ -507,14 +669,20 @@ impl Adapter { unsafe extern "C" fn get_voltage_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| T::get_voltage(&rdev)) } unsafe extern "C" fn get_voltage_sel_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| T::get_voltage_sel(&rdev)) } @@ -523,7 +691,10 @@ impl Adapter { min_ua: core::ffi::c_int, max_ua: core::ffi::c_int, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::set_current_limit(&rdev, min_ua, max_ua)?; Ok(0) @@ -533,7 +704,10 @@ impl Adapter { unsafe extern "C" fn get_current_limit_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| T::get_current_limit(&rdev)) } @@ -541,7 +715,10 @@ impl Adapter { rdev: *mut bindings::regulator_dev, enable: bool, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::set_active_discharge(&rdev, enable)?; Ok(0) @@ -549,7 +726,10 @@ impl Adapter { } unsafe extern "C" fn enable_callback(rdev: *mut bindings::regulator_dev) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::enable(&rdev)?; Ok(0) @@ -557,7 +737,10 @@ impl Adapter { } unsafe extern "C" fn disable_callback(rdev: *mut bindings::regulator_dev) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::disable(&rdev)?; Ok(0) @@ -567,7 +750,10 @@ impl Adapter { unsafe extern "C" fn is_enabled_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::is_enabled(&rdev)?; Ok(0) @@ -578,7 +764,10 @@ impl Adapter { rdev: *mut bindings::regulator_dev, mode: core::ffi::c_uint, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { let mode = Mode::try_from(mode).unwrap_or(Mode::Invalid); T::set_mode(&rdev, mode)?; @@ -589,14 +778,20 @@ impl Adapter { unsafe extern "C" fn get_mode_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_uint { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); T::get_mode(&rdev) as _ } unsafe extern "C" fn get_status_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| Ok(T::get_status(&rdev)? as _)) } @@ -604,7 +799,10 @@ impl Adapter { rdev: *mut bindings::regulator_dev, uv: core::ffi::c_int, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::set_suspend_voltage(&rdev, uv)?; Ok(0) @@ -614,7 +812,10 @@ impl Adapter { unsafe extern "C" fn set_suspend_enable_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::set_suspend_enable(&rdev)?; Ok(0) @@ -624,7 +825,10 @@ impl Adapter { unsafe extern "C" fn set_suspend_disable_callback( rdev: *mut bindings::regulator_dev, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { T::set_suspend_disable(&rdev)?; Ok(0) @@ -635,7 +839,10 @@ impl Adapter { rdev: *mut bindings::regulator_dev, mode: core::ffi::c_uint, ) -> core::ffi::c_int { - let rdev = ManuallyDrop::new(Regulator { rdev }); + let rdev = ManuallyDrop::new(Regulator { + rdev, + _regmap: None, + }); from_result(|| { let mode = Mode::try_from(mode).unwrap_or(Mode::Invalid); T::set_suspend_mode(&rdev, mode)?;