1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
// SPDX-License-Identifier: GPL-2.0
//! Common clock framework.
//!
//! C header: [`include/linux/clk.h`](../../../../include/linux/clk.h)
use crate::{bindings, error::Result, to_result};
use core::mem::ManuallyDrop;
/// Represents `struct clk *`.
///
/// # Invariants
///
/// The pointer is valid.
pub struct Clk(*mut bindings::clk);
impl Clk {
/// Creates new clock structure from a raw pointer.
///
/// # Safety
///
/// The pointer must be valid.
pub unsafe fn new(clk: *mut bindings::clk) -> Self {
Self(clk)
}
/// Returns value of the rate field of `struct clk`.
pub fn get_rate(&self) -> usize {
// SAFETY: The pointer is valid by the type invariant.
unsafe { bindings::clk_get_rate(self.0) as usize }
}
/// Prepares and enables the underlying hardware clock.
///
/// This function should not be called in atomic context.
pub fn prepare_enable(self) -> Result<EnabledClk> {
// SAFETY: The pointer is valid by the type invariant.
to_result(unsafe { bindings::clk_prepare_enable(self.0) })?;
Ok(EnabledClk(self))
}
}
impl Drop for Clk {
fn drop(&mut self) {
// SAFETY: The pointer is valid by the type invariant.
unsafe { bindings::clk_put(self.0) };
}
}
// SAFETY: `Clk` is not restricted to a single thread so it is safe
// to move it between threads.
unsafe impl Send for Clk {}
/// A clock variant that is prepared and enabled.
pub struct EnabledClk(Clk);
impl EnabledClk {
/// Returns value of the rate field of `struct clk`.
pub fn get_rate(&self) -> usize {
self.0.get_rate()
}
/// Disables and later unprepares the underlying hardware clock prematurely.
///
/// This function should not be called in atomic context.
pub fn disable_unprepare(self) -> Clk {
let mut clk = ManuallyDrop::new(self);
// SAFETY: The pointer is valid by the type invariant.
unsafe { bindings::clk_disable_unprepare(clk.0 .0) };
core::mem::replace(&mut clk.0, Clk(core::ptr::null_mut()))
}
}
impl Drop for EnabledClk {
fn drop(&mut self) {
// SAFETY: The pointer is valid by the type invariant.
unsafe { bindings::clk_disable_unprepare(self.0 .0) };
}
}