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