From 0b4251203bf0c2c603d73e1e460c7f069c08e156 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Fri, 1 Mar 2024 13:00:07 -0800 Subject: [PATCH] rust: regulator: Add support for regmap The regulator API offer many helpers to help simplifies drivers that use the regmap API. This commit adds partial support for it, only the function needed by the NCV6336 driver were added. In case CONFIG_REGMAP=n, we create a dummy Regmap implementation in order to avoid to have to surround a lot of the declarations and statements with #[cfg(CONFIG_REGMAP)]. Signed-off-by: Fabien Parent --- rust/kernel/regulator/driver.rs | 247 +++++++++++++++++++++++++++++--- 1 file changed, 227 insertions(+), 20 deletions(-) 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)?;