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::*;