Many drivers only need a clock running for as long as the device is bound and never touch it afterwards. In C, devm_clk_get_enabled() and devm_clk_get_optional_enabled() cover this case.
Add devm_enable(), devm_enable_optional() and devm_enable_optional_with_rate(), which wrap the C helpers. They return no handle, so the driver keeps nothing in its data and cannot change the state of the clock. The clock is disabled, unprepared and put when the device is unbound. This mirrors regulator::devm_enable() and devm_enable_optional(). Reviewed-by: Alexandre Courbot <[email protected]> Signed-off-by: Daniel Almeida <[email protected]> --- rust/kernel/clk.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index 93b4dc17f0ad..e2587c613182 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -121,6 +121,52 @@ impl Sealed for super::Prepared {} impl Sealed for super::Enabled {} } + /// Obtains and enables a [`devres`]-managed [`Clk`] for a bound device. + /// + /// [`devres`]: crate::devres::Devres + #[inline] + pub fn devm_enable(dev: &Device<Bound>, name: Option<&CStr>) -> Result { + let name = name.map_or(ptr::null(), |n| n.as_char_ptr()); + + // SAFETY: It is safe to call `devm_clk_get_enabled()` for a valid device + // pointer and any `name`, including NULL. + from_err_ptr(unsafe { bindings::devm_clk_get_enabled(dev.as_raw(), name) })?; + Ok(()) + } + + /// Obtains and enables an optional [`devres`]-managed [`Clk`] for a bound + /// device. + /// + /// If the clock does not exist, this succeeds and does nothing. + /// + /// [`devres`]: crate::devres::Devres + #[inline] + pub fn devm_enable_optional(dev: &Device<Bound>, name: Option<&CStr>) -> Result { + let name = name.map_or(ptr::null(), |n| n.as_char_ptr()); + + // SAFETY: It is safe to call `devm_clk_get_optional_enabled()` for a + // valid device pointer and any `name`, including NULL. + from_err_ptr(unsafe { bindings::devm_clk_get_optional_enabled(dev.as_raw(), name) })?; + Ok(()) + } + + /// Same as [`devm_enable_optional`], but also sets the rate. + #[inline] + pub fn devm_enable_optional_with_rate( + dev: &Device<Bound>, + name: Option<&CStr>, + rate: Hertz, + ) -> Result { + let name = name.map_or(ptr::null(), |n| n.as_char_ptr()); + + // SAFETY: It is safe to call `devm_clk_get_optional_enabled_with_rate()` + // for a valid device pointer and any `name`, including NULL. + from_err_ptr(unsafe { + bindings::devm_clk_get_optional_enabled_with_rate(dev.as_raw(), name, rate.as_hz()) + })?; + Ok(()) + } + /// A trait representing the different states that a [`Clk`] can be in. pub trait ClkState: private::Sealed { /// Whether the clock is enabled in this state. -- 2.56.0
