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