[PATCH v4 1/2] rust: clk: Add `ExclusiveClk` wrapper for `clk_rate_exclusive_get`
Maurice Hieronymus <[email protected]> Sat, 11 Jul 2026 12:16:29 +0200
| Newsgroups | org.kernel.vger.linux-pwm,org.infradead.lists.linux-riscv,org.kernel.vger.linux-clk,org.kernel.vger.linux-kernel,org.kernel.vger.rust-for-linux |
|---|---|
| Message-ID | <[email protected]> |
Add Rust bindings for `clk_rate_exclusive_get()` and `clk_rate_exclusive_put()`. `Clk::rate_exclusive_get()` consumes the `Clk<Enabled>` and returns an `ExclusiveClk`. The matching put is issued from its Drop impl. `ExclusiveClk` derefs to `Clk<Enabled>` so existing APIs remain available on the locked handle. Reviewed-by: Alice Ryhl <[email protected]> Signed-off-by: Maurice Hieronymus <[email protected]> --- rust/kernel/clk.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index e677156ffd21..18e4c1fb0937 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -95,6 +95,7 @@ mod common_clk { use core::{ marker::PhantomData, mem::ManuallyDrop, + ops::Deref, ptr, // }; @@ -682,6 +683,23 @@ pub fn disable(self) -> Clk<Prepared> { _phantom: PhantomData, } } + + /// Acquire exclusive control over the clock's rate. + /// + /// Consumes the [`Clk<Enabled>`] and returns an [`ExclusiveClk`] that releases + /// the exclusivity when dropped. While held, no other consumer may change the clock's rate. + /// + /// Equivalent to the kernel's [`clk_rate_exclusive_get`] API. Must not be called from + /// atomic context. + /// + /// [`clk_rate_exclusive_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_rate_exclusive_get + #[inline] + pub fn rate_exclusive_get(self) -> Result<ExclusiveClk> { + // SAFETY: By the type invariants, self.as_raw() is a valid argument for + // clk_rate_exclusive_get. + to_result(unsafe { bindings::clk_rate_exclusive_get(self.as_raw()) })?; + Ok(ExclusiveClk(self)) + } } impl<T: ClkState> Clk<T> { @@ -767,6 +785,55 @@ fn clone(&self) -> Self { } } } + + /// A [`Clk<Enabled>`] with exclusive control over its rate. + /// + /// While an [`ExclusiveClk`] exists, no other consumer of the same clock may change its rate. + /// Obtained by calling [`Clk::rate_exclusive_get`]; the exclusivity is released automatically + /// when the value is dropped, after which the inner [`Clk<Enabled>`] is dropped as usual. + /// + /// # Invariants + /// + /// An [`ExclusiveClk`] instance owns a [`Clk<Enabled>`] for which `clk_rate_exclusive_get` has + /// been called and the matching `clk_rate_exclusive_put` has not yet been called. + /// + /// # Examples + /// + /// ``` + /// use kernel::clk::{ + /// Clk, + /// ExclusiveClk, + /// Enabled // + /// }; + /// use kernel::device::{ + /// Bound, + /// Device, // + /// }; + /// use kernel::error::Result; + /// + /// fn lock_rate(dev: &Device<Bound>) -> Result<ExclusiveClk> { + /// let clk = Clk::<Enabled>::get(dev, None)?; + /// clk.rate_exclusive_get() + /// } + /// ``` + pub struct ExclusiveClk(Clk<Enabled>); + + impl Deref for ExclusiveClk { + type Target = Clk<Enabled>; + + fn deref(&self) -> &Clk<Enabled> { + &self.0 + } + } + + impl Drop for ExclusiveClk { + fn drop(&mut self) { + // SAFETY: By the type invariants, self.as_raw() is a valid argument for + // clk_rate_exclusive_put and balances the clk_rate_exclusive_get call from + // Clk::rate_exclusive_get. + unsafe { bindings::clk_rate_exclusive_put(self.as_raw()) }; + } + } } #[cfg(CONFIG_COMMON_CLK)] -- 2.51.2