xref: /linux/rust/kernel/clk.rs (revision 0c0695a9d8c97f63d71dc890faa6999eef728f57)
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 
9 use 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)]
30 pub struct Hertz(pub c_ulong);
31 
32 impl 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 
73 impl From<Hertz> for c_ulong {
74     fn from(freq: Hertz) -> Self {
75         freq.0
76     }
77 }
78 
79 #[cfg(CONFIG_COMMON_CLK)]
80 mod 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::clk::{Clk, Hertz};
108     /// use kernel::device::Device;
109     /// use kernel::error::Result;
110     ///
111     /// fn configure_clk(dev: &Device) -> Result {
112     ///     let clk = Clk::get(dev, Some(c"apb_clk"))?;
113     ///
114     ///     clk.prepare_enable()?;
115     ///
116     ///     let expected_rate = Hertz::from_ghz(1);
117     ///
118     ///     if clk.rate() != expected_rate {
119     ///         clk.set_rate(expected_rate)?;
120     ///     }
121     ///
122     ///     clk.disable_unprepare();
123     ///     Ok(())
124     /// }
125     /// ```
126     ///
127     /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html
128     #[repr(transparent)]
129     pub struct Clk(*mut bindings::clk);
130 
131     // SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called.
132     unsafe impl Send for Clk {}
133 
134     // SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the
135     // methods are synchronized internally.
136     unsafe impl Sync for Clk {}
137 
138     impl Clk {
139         /// Gets [`Clk`] corresponding to a [`Device`] and a connection id.
140         ///
141         /// Equivalent to the kernel's [`clk_get`] API.
142         ///
143         /// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get
144         pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
145             let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
146 
147             // SAFETY: It is safe to call [`clk_get`] for a valid device pointer.
148             //
149             // INVARIANT: The reference-count is decremented when [`Clk`] goes out of scope.
150             Ok(Self(from_err_ptr(unsafe {
151                 bindings::clk_get(dev.as_raw(), con_id)
152             })?))
153         }
154 
155         /// Obtain the raw [`struct clk`] pointer.
156         #[inline]
157         pub fn as_raw(&self) -> *mut bindings::clk {
158             self.0
159         }
160 
161         /// Enable the clock.
162         ///
163         /// Equivalent to the kernel's [`clk_enable`] API.
164         ///
165         /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable
166         #[inline]
167         pub fn enable(&self) -> Result {
168             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
169             // [`clk_enable`].
170             to_result(unsafe { bindings::clk_enable(self.as_raw()) })
171         }
172 
173         /// Disable the clock.
174         ///
175         /// Equivalent to the kernel's [`clk_disable`] API.
176         ///
177         /// [`clk_disable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_disable
178         #[inline]
179         pub fn disable(&self) {
180             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
181             // [`clk_disable`].
182             unsafe { bindings::clk_disable(self.as_raw()) };
183         }
184 
185         /// Prepare the clock.
186         ///
187         /// Equivalent to the kernel's [`clk_prepare`] API.
188         ///
189         /// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_prepare
190         #[inline]
191         pub fn prepare(&self) -> Result {
192             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
193             // [`clk_prepare`].
194             to_result(unsafe { bindings::clk_prepare(self.as_raw()) })
195         }
196 
197         /// Unprepare the clock.
198         ///
199         /// Equivalent to the kernel's [`clk_unprepare`] API.
200         ///
201         /// [`clk_unprepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_unprepare
202         #[inline]
203         pub fn unprepare(&self) {
204             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
205             // [`clk_unprepare`].
206             unsafe { bindings::clk_unprepare(self.as_raw()) };
207         }
208 
209         /// Prepare and enable the clock.
210         ///
211         /// Equivalent to calling [`Clk::prepare`] followed by [`Clk::enable`].
212         #[inline]
213         pub fn prepare_enable(&self) -> Result {
214             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
215             // [`clk_prepare_enable`].
216             to_result(unsafe { bindings::clk_prepare_enable(self.as_raw()) })
217         }
218 
219         /// Disable and unprepare the clock.
220         ///
221         /// Equivalent to calling [`Clk::disable`] followed by [`Clk::unprepare`].
222         #[inline]
223         pub fn disable_unprepare(&self) {
224             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
225             // [`clk_disable_unprepare`].
226             unsafe { bindings::clk_disable_unprepare(self.as_raw()) };
227         }
228 
229         /// Get clock's rate.
230         ///
231         /// Equivalent to the kernel's [`clk_get_rate`] API.
232         ///
233         /// [`clk_get_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_rate
234         #[inline]
235         pub fn rate(&self) -> Hertz {
236             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
237             // [`clk_get_rate`].
238             Hertz(unsafe { bindings::clk_get_rate(self.as_raw()) })
239         }
240 
241         /// Set clock's rate.
242         ///
243         /// Equivalent to the kernel's [`clk_set_rate`] API.
244         ///
245         /// [`clk_set_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_set_rate
246         #[inline]
247         pub fn set_rate(&self, rate: Hertz) -> Result {
248             // SAFETY: By the type invariants, self.as_raw() is a valid argument for
249             // [`clk_set_rate`].
250             to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) })
251         }
252     }
253 
254     impl Drop for Clk {
255         fn drop(&mut self) {
256             // SAFETY: By the type invariants, self.as_raw() is a valid argument for [`clk_put`].
257             unsafe { bindings::clk_put(self.as_raw()) };
258         }
259     }
260 
261     /// A reference-counted optional clock.
262     ///
263     /// A lightweight wrapper around an optional [`Clk`]. An [`OptionalClk`] represents a [`Clk`]
264     /// that a driver can function without but may improve performance or enable additional
265     /// features when available.
266     ///
267     /// # Invariants
268     ///
269     /// An [`OptionalClk`] instance encapsulates a [`Clk`] with either a valid [`struct clk`] or
270     /// `NULL` pointer.
271     ///
272     /// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the
273     /// allocation remains valid for the lifetime of the [`OptionalClk`].
274     ///
275     /// # Examples
276     ///
277     /// The following example demonstrates how to obtain and configure an optional clock for a
278     /// device. The code functions correctly whether or not the clock is available.
279     ///
280     /// ```
281     /// use kernel::clk::{OptionalClk, Hertz};
282     /// use kernel::device::Device;
283     /// use kernel::error::Result;
284     ///
285     /// fn configure_clk(dev: &Device) -> Result {
286     ///     let clk = OptionalClk::get(dev, Some(c"apb_clk"))?;
287     ///
288     ///     clk.prepare_enable()?;
289     ///
290     ///     let expected_rate = Hertz::from_ghz(1);
291     ///
292     ///     if clk.rate() != expected_rate {
293     ///         clk.set_rate(expected_rate)?;
294     ///     }
295     ///
296     ///     clk.disable_unprepare();
297     ///     Ok(())
298     /// }
299     /// ```
300     ///
301     /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html
302     pub struct OptionalClk(Clk);
303 
304     impl OptionalClk {
305         /// Gets [`OptionalClk`] corresponding to a [`Device`] and a connection id.
306         ///
307         /// Equivalent to the kernel's [`clk_get_optional`] API.
308         ///
309         /// [`clk_get_optional`]:
310         /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional
311         pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
312             let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
313 
314             // SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer.
315             //
316             // INVARIANT: The reference-count is decremented when [`OptionalClk`] goes out of
317             // scope.
318             Ok(Self(Clk(from_err_ptr(unsafe {
319                 bindings::clk_get_optional(dev.as_raw(), con_id)
320             })?)))
321         }
322     }
323 
324     // Make [`OptionalClk`] behave like [`Clk`].
325     impl Deref for OptionalClk {
326         type Target = Clk;
327 
328         fn deref(&self) -> &Clk {
329             &self.0
330         }
331     }
332 }
333 
334 #[cfg(CONFIG_COMMON_CLK)]
335 pub use common_clk::*;
336