[PATCH v3 1/2] rust: clk: Add `ExclusiveClk` wrapper for `clk_rate_exclusive_get`

From: Maurice Hieronymus

Date: Sun Jun 28 2026 - 16:19:26 EST


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 <aliceryhl@xxxxxxxxxx>
Signed-off-by: Maurice Hieronymus <mhi@xxxxxxxxxxx>
---
rust/kernel/clk.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)

diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index 1412a2f0aedf..89f662b67b95 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, //
};

@@ -621,6 +622,23 @@ pub fn set_rate(&self, rate: Hertz) -> Result {
// [`clk_set_rate`].
to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) })
}
+
+ /// 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> {
@@ -650,6 +668,55 @@ fn drop(&mut self) {
unsafe { bindings::clk_put(self.as_raw()) };
}
}
+
+ /// 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