kernel/
clk.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Clock abstractions.
4//!
5//! C header: [`include/linux/clk.h`](srctree/include/linux/clk.h)
6//!
7//! Reference: <https://docs.kernel.org/driver-api/clk.html>
8
9use crate::ffi::c_ulong;
10
11/// The frequency unit.
12///
13/// Represents a frequency in hertz, wrapping a [`c_ulong`] value.
14///
15/// # Examples
16///
17/// ```
18/// use kernel::clk::Hertz;
19///
20/// let hz = 1_000_000_000;
21/// let rate = Hertz(hz);
22///
23/// assert_eq!(rate.as_hz(), hz);
24/// assert_eq!(rate, Hertz(hz));
25/// assert_eq!(rate, Hertz::from_khz(hz / 1_000));
26/// assert_eq!(rate, Hertz::from_mhz(hz / 1_000_000));
27/// assert_eq!(rate, Hertz::from_ghz(hz / 1_000_000_000));
28/// ```
29#[derive(Copy, Clone, PartialEq, Eq, Debug)]
30pub struct Hertz(pub c_ulong);
31
32impl Hertz {
33    const KHZ_TO_HZ: c_ulong = 1_000;
34    const MHZ_TO_HZ: c_ulong = 1_000_000;
35    const GHZ_TO_HZ: c_ulong = 1_000_000_000;
36
37    /// Create a new instance from kilohertz (kHz)
38    pub const fn from_khz(khz: c_ulong) -> Self {
39        Self(khz * Self::KHZ_TO_HZ)
40    }
41
42    /// Create a new instance from megahertz (MHz)
43    pub const fn from_mhz(mhz: c_ulong) -> Self {
44        Self(mhz * Self::MHZ_TO_HZ)
45    }
46
47    /// Create a new instance from gigahertz (GHz)
48    pub const fn from_ghz(ghz: c_ulong) -> Self {
49        Self(ghz * Self::GHZ_TO_HZ)
50    }
51
52    /// Get the frequency in hertz
53    pub const fn as_hz(&self) -> c_ulong {
54        self.0
55    }
56
57    /// Get the frequency in kilohertz
58    pub const fn as_khz(&self) -> c_ulong {
59        self.0 / Self::KHZ_TO_HZ
60    }
61
62    /// Get the frequency in megahertz
63    pub const fn as_mhz(&self) -> c_ulong {
64        self.0 / Self::MHZ_TO_HZ
65    }
66
67    /// Get the frequency in gigahertz
68    pub const fn as_ghz(&self) -> c_ulong {
69        self.0 / Self::GHZ_TO_HZ
70    }
71}
72
73impl From<Hertz> for c_ulong {
74    fn from(freq: Hertz) -> Self {
75        freq.0
76    }
77}
78
79#[cfg(CONFIG_COMMON_CLK)]
80mod common_clk {
81    use super::Hertz;
82    use crate::{
83        device::Device,
84        error::{from_err_ptr, to_result, Result},
85        prelude::*,
86    };
87
88    use core::{ops::Deref, ptr};
89
90    /// A reference-counted clock.
91    ///
92    /// Rust abstraction for the C [`struct clk`].
93    ///
94    /// # Invariants
95    ///
96    /// A [`Clk`] instance holds either a pointer to a valid [`struct clk`] created by the C
97    /// portion of the kernel or a NULL pointer.
98    ///
99    /// Instances of this type are reference-counted. Calling [`Clk::get`] ensures that the
100    /// allocation remains valid for the lifetime of the [`Clk`].
101    ///
102    /// # Examples
103    ///
104    /// The following example demonstrates how to obtain and configure a clock for a device.
105    ///
106    /// ```
107    /// use kernel::c_str;
108    /// use kernel::clk::{Clk, Hertz};
109    /// use kernel::device::Device;
110    /// use kernel::error::Result;
111    ///
112    /// fn configure_clk(dev: &Device) -> Result {
113    ///     let clk = Clk::get(dev, Some(c_str!("apb_clk")))?;
114    ///
115    ///     clk.prepare_enable()?;
116    ///
117    ///     let expected_rate = Hertz::from_ghz(1);
118    ///
119    ///     if clk.rate() != expected_rate {
120    ///         clk.set_rate(expected_rate)?;
121    ///     }
122    ///
123    ///     clk.disable_unprepare();
124    ///     Ok(())
125    /// }
126    /// ```
127    ///
128    /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html
129    #[repr(transparent)]
130    pub struct Clk(*mut bindings::clk);
131
132    // SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called.
133    unsafe impl Send for Clk {}
134
135    // SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the
136    // methods are synchronized internally.
137    unsafe impl Sync for Clk {}
138
139    impl Clk {
140        /// Gets [`Clk`] corresponding to a [`Device`] and a connection id.
141        ///
142        /// Equivalent to the kernel's [`clk_get`] API.
143        ///
144        /// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get
145        pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
146            let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
147
148            // SAFETY: It is safe to call [`clk_get`] for a valid device pointer.
149            //
150            // INVARIANT: The reference-count is decremented when [`Clk`] goes out of scope.
151            Ok(Self(from_err_ptr(unsafe {
152                bindings::clk_get(dev.as_raw(), con_id)
153            })?))
154        }
155
156        /// Obtain the raw [`struct clk`] pointer.
157        #[inline]
158        pub fn as_raw(&self) -> *mut bindings::clk {
159            self.0
160        }
161
162        /// Enable the clock.
163        ///
164        /// Equivalent to the kernel's [`clk_enable`] API.
165        ///
166        /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable
167        #[inline]
168        pub fn enable(&self) -> Result {
169            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
170            // [`clk_enable`].
171            to_result(unsafe { bindings::clk_enable(self.as_raw()) })
172        }
173
174        /// Disable the clock.
175        ///
176        /// Equivalent to the kernel's [`clk_disable`] API.
177        ///
178        /// [`clk_disable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_disable
179        #[inline]
180        pub fn disable(&self) {
181            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
182            // [`clk_disable`].
183            unsafe { bindings::clk_disable(self.as_raw()) };
184        }
185
186        /// Prepare the clock.
187        ///
188        /// Equivalent to the kernel's [`clk_prepare`] API.
189        ///
190        /// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_prepare
191        #[inline]
192        pub fn prepare(&self) -> Result {
193            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
194            // [`clk_prepare`].
195            to_result(unsafe { bindings::clk_prepare(self.as_raw()) })
196        }
197
198        /// Unprepare the clock.
199        ///
200        /// Equivalent to the kernel's [`clk_unprepare`] API.
201        ///
202        /// [`clk_unprepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_unprepare
203        #[inline]
204        pub fn unprepare(&self) {
205            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
206            // [`clk_unprepare`].
207            unsafe { bindings::clk_unprepare(self.as_raw()) };
208        }
209
210        /// Prepare and enable the clock.
211        ///
212        /// Equivalent to calling [`Clk::prepare`] followed by [`Clk::enable`].
213        #[inline]
214        pub fn prepare_enable(&self) -> Result {
215            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
216            // [`clk_prepare_enable`].
217            to_result(unsafe { bindings::clk_prepare_enable(self.as_raw()) })
218        }
219
220        /// Disable and unprepare the clock.
221        ///
222        /// Equivalent to calling [`Clk::disable`] followed by [`Clk::unprepare`].
223        #[inline]
224        pub fn disable_unprepare(&self) {
225            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
226            // [`clk_disable_unprepare`].
227            unsafe { bindings::clk_disable_unprepare(self.as_raw()) };
228        }
229
230        /// Get clock's rate.
231        ///
232        /// Equivalent to the kernel's [`clk_get_rate`] API.
233        ///
234        /// [`clk_get_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_rate
235        #[inline]
236        pub fn rate(&self) -> Hertz {
237            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
238            // [`clk_get_rate`].
239            Hertz(unsafe { bindings::clk_get_rate(self.as_raw()) })
240        }
241
242        /// Set clock's rate.
243        ///
244        /// Equivalent to the kernel's [`clk_set_rate`] API.
245        ///
246        /// [`clk_set_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_set_rate
247        #[inline]
248        pub fn set_rate(&self, rate: Hertz) -> Result {
249            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
250            // [`clk_set_rate`].
251            to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) })
252        }
253    }
254
255    impl Drop for Clk {
256        fn drop(&mut self) {
257            // SAFETY: By the type invariants, self.as_raw() is a valid argument for [`clk_put`].
258            unsafe { bindings::clk_put(self.as_raw()) };
259        }
260    }
261
262    /// A reference-counted optional clock.
263    ///
264    /// A lightweight wrapper around an optional [`Clk`]. An [`OptionalClk`] represents a [`Clk`]
265    /// that a driver can function without but may improve performance or enable additional
266    /// features when available.
267    ///
268    /// # Invariants
269    ///
270    /// An [`OptionalClk`] instance encapsulates a [`Clk`] with either a valid [`struct clk`] or
271    /// `NULL` pointer.
272    ///
273    /// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the
274    /// allocation remains valid for the lifetime of the [`OptionalClk`].
275    ///
276    /// # Examples
277    ///
278    /// The following example demonstrates how to obtain and configure an optional clock for a
279    /// device. The code functions correctly whether or not the clock is available.
280    ///
281    /// ```
282    /// use kernel::c_str;
283    /// use kernel::clk::{OptionalClk, Hertz};
284    /// use kernel::device::Device;
285    /// use kernel::error::Result;
286    ///
287    /// fn configure_clk(dev: &Device) -> Result {
288    ///     let clk = OptionalClk::get(dev, Some(c_str!("apb_clk")))?;
289    ///
290    ///     clk.prepare_enable()?;
291    ///
292    ///     let expected_rate = Hertz::from_ghz(1);
293    ///
294    ///     if clk.rate() != expected_rate {
295    ///         clk.set_rate(expected_rate)?;
296    ///     }
297    ///
298    ///     clk.disable_unprepare();
299    ///     Ok(())
300    /// }
301    /// ```
302    ///
303    /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html
304    pub struct OptionalClk(Clk);
305
306    impl OptionalClk {
307        /// Gets [`OptionalClk`] corresponding to a [`Device`] and a connection id.
308        ///
309        /// Equivalent to the kernel's [`clk_get_optional`] API.
310        ///
311        /// [`clk_get_optional`]:
312        /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional
313        pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
314            let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
315
316            // SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer.
317            //
318            // INVARIANT: The reference-count is decremented when [`OptionalClk`] goes out of
319            // scope.
320            Ok(Self(Clk(from_err_ptr(unsafe {
321                bindings::clk_get_optional(dev.as_raw(), con_id)
322            })?)))
323        }
324    }
325
326    // Make [`OptionalClk`] behave like [`Clk`].
327    impl Deref for OptionalClk {
328        type Target = Clk;
329
330        fn deref(&self) -> &Clk {
331            &self.0
332        }
333    }
334}
335
336#[cfg(CONFIG_COMMON_CLK)]
337pub use common_clk::*;