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 /// Create a new instance from kilohertz (kHz)
34 pub fn from_khz(khz: c_ulong) -> Self {
35 Self(khz * 1_000)
36 }
37
38 /// Create a new instance from megahertz (MHz)
39 pub fn from_mhz(mhz: c_ulong) -> Self {
40 Self(mhz * 1_000_000)
41 }
42
43 /// Create a new instance from gigahertz (GHz)
44 pub fn from_ghz(ghz: c_ulong) -> Self {
45 Self(ghz * 1_000_000_000)
46 }
47
48 /// Get the frequency in hertz
49 pub fn as_hz(&self) -> c_ulong {
50 self.0
51 }
52
53 /// Get the frequency in kilohertz
54 pub fn as_khz(&self) -> c_ulong {
55 self.0 / 1_000
56 }
57
58 /// Get the frequency in megahertz
59 pub fn as_mhz(&self) -> c_ulong {
60 self.0 / 1_000_000
61 }
62
63 /// Get the frequency in gigahertz
64 pub fn as_ghz(&self) -> c_ulong {
65 self.0 / 1_000_000_000
66 }
67}
68
69impl From<Hertz> for c_ulong {
70 fn from(freq: Hertz) -> Self {
71 freq.0
72 }
73}
74
75#[cfg(CONFIG_COMMON_CLK)]
76mod 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
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]
151 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]
161 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]
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]
185 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]
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]
207 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]
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]
229 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]
241 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 {
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
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
327 fn deref(&self) -> &Clk {
328 &self.0
329 }
330 }
331}
332
333#[cfg(CONFIG_COMMON_CLK)]
334pub use common_clk::*;