Skip to content

Commit d01d702

Browse files
committed
rust: clk: Add initial abstractions
Add initial abstractions for the clk APIs. These provide the minimal functionality needed for common use cases, making them straightforward to introduce in the first iteration. These will be used by Rust based cpufreq / OPP layers to begin with. Tested-by: Daniel Almeida <[email protected]> Reviewed-by: Daniel Almeida <[email protected]> Signed-off-by: Viresh Kumar <[email protected]>
1 parent b7b7b98 commit d01d702

File tree

3 files changed

+336
-0
lines changed

3 files changed

+336
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5884,6 +5884,7 @@ F: include/linux/clk-pr*
58845884
F: include/linux/clk/
58855885
F: include/linux/of_clk.h
58865886
F: rust/helpers/clk.c
5887+
F: rust/kernel/clk.rs
58875888
X: drivers/clk/clkdev.c
58885889

58895890
COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3)

rust/kernel/clk.rs

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
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)
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+
69+
impl From<Hertz> for c_ulong {
70+
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
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)]
334+
pub use common_clk::*;

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub mod alloc;
4242
pub mod block;
4343
#[doc(hidden)]
4444
pub mod build_assert;
45+
pub mod clk;
4546
pub mod cpumask;
4647
pub mod cred;
4748
pub mod device;

0 commit comments

Comments
 (0)