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