// SPDX-License-Identifier: GPL-2.012//! Clock abstractions.3//!4//! C header: [`include/linux/clk.h`](srctree/include/linux/clk.h)5//!6//! Reference: <https://docs.kernel.org/driver-api/clk.html>78use crate::ffi::c_ulong;910/// The frequency unit.11///12/// Represents a frequency in hertz, wrapping a [`c_ulong`] value.13///14/// # Examples15///16/// ```17/// use kernel::clk::Hertz;18///19/// let hz = 1_000_000_000;20/// let rate = Hertz(hz);21///22/// assert_eq!(rate.as_hz(), hz);23/// assert_eq!(rate, Hertz(hz));24/// assert_eq!(rate, Hertz::from_khz(hz / 1_000));25/// assert_eq!(rate, Hertz::from_mhz(hz / 1_000_000));26/// assert_eq!(rate, Hertz::from_ghz(hz / 1_000_000_000));27/// ```28#[derive(Copy, Clone, PartialEq, Eq, Debug)]29pub struct Hertz(pub c_ulong);3031impl Hertz {32const KHZ_TO_HZ: c_ulong = 1_000;33const MHZ_TO_HZ: c_ulong = 1_000_000;34const GHZ_TO_HZ: c_ulong = 1_000_000_000;3536/// Create a new instance from kilohertz (kHz)37pub const fn from_khz(khz: c_ulong) -> Self {38Self(khz * Self::KHZ_TO_HZ)39}4041/// Create a new instance from megahertz (MHz)42pub const fn from_mhz(mhz: c_ulong) -> Self {43Self(mhz * Self::MHZ_TO_HZ)44}4546/// Create a new instance from gigahertz (GHz)47pub const fn from_ghz(ghz: c_ulong) -> Self {48Self(ghz * Self::GHZ_TO_HZ)49}5051/// Get the frequency in hertz52pub const fn as_hz(&self) -> c_ulong {53self.054}5556/// Get the frequency in kilohertz57pub const fn as_khz(&self) -> c_ulong {58self.0 / Self::KHZ_TO_HZ59}6061/// Get the frequency in megahertz62pub const fn as_mhz(&self) -> c_ulong {63self.0 / Self::MHZ_TO_HZ64}6566/// Get the frequency in gigahertz67pub const fn as_ghz(&self) -> c_ulong {68self.0 / Self::GHZ_TO_HZ69}70}7172impl From<Hertz> for c_ulong {73fn from(freq: Hertz) -> Self {74freq.075}76}7778#[cfg(CONFIG_COMMON_CLK)]79mod common_clk {80use super::Hertz;81use crate::{82device::Device,83error::{from_err_ptr, to_result, Result},84prelude::*,85};8687use core::{ops::Deref, ptr};8889/// A reference-counted clock.90///91/// Rust abstraction for the C [`struct clk`].92///93/// # Invariants94///95/// A [`Clk`] instance holds either a pointer to a valid [`struct clk`] created by the C96/// portion of the kernel or a NULL pointer.97///98/// Instances of this type are reference-counted. Calling [`Clk::get`] ensures that the99/// allocation remains valid for the lifetime of the [`Clk`].100///101/// # Examples102///103/// The following example demonstrates how to obtain and configure a clock for a device.104///105/// ```106/// use kernel::c_str;107/// use kernel::clk::{Clk, Hertz};108/// use kernel::device::Device;109/// use kernel::error::Result;110///111/// fn configure_clk(dev: &Device) -> Result {112/// let clk = Clk::get(dev, Some(c_str!("apb_clk")))?;113///114/// clk.prepare_enable()?;115///116/// let expected_rate = Hertz::from_ghz(1);117///118/// if clk.rate() != expected_rate {119/// clk.set_rate(expected_rate)?;120/// }121///122/// clk.disable_unprepare();123/// Ok(())124/// }125/// ```126///127/// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html128#[repr(transparent)]129pub struct Clk(*mut bindings::clk);130131impl Clk {132/// Gets [`Clk`] corresponding to a [`Device`] and a connection id.133///134/// Equivalent to the kernel's [`clk_get`] API.135///136/// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get137pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {138let con_id = name.map_or(ptr::null(), |n| n.as_ptr());139140// SAFETY: It is safe to call [`clk_get`] for a valid device pointer.141//142// INVARIANT: The reference-count is decremented when [`Clk`] goes out of scope.143Ok(Self(from_err_ptr(unsafe {144bindings::clk_get(dev.as_raw(), con_id)145})?))146}147148/// Obtain the raw [`struct clk`] pointer.149#[inline]150pub fn as_raw(&self) -> *mut bindings::clk {151self.0152}153154/// Enable the clock.155///156/// Equivalent to the kernel's [`clk_enable`] API.157///158/// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable159#[inline]160pub fn enable(&self) -> Result {161// SAFETY: By the type invariants, self.as_raw() is a valid argument for162// [`clk_enable`].163to_result(unsafe { bindings::clk_enable(self.as_raw()) })164}165166/// Disable the clock.167///168/// Equivalent to the kernel's [`clk_disable`] API.169///170/// [`clk_disable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_disable171#[inline]172pub fn disable(&self) {173// SAFETY: By the type invariants, self.as_raw() is a valid argument for174// [`clk_disable`].175unsafe { bindings::clk_disable(self.as_raw()) };176}177178/// Prepare the clock.179///180/// Equivalent to the kernel's [`clk_prepare`] API.181///182/// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_prepare183#[inline]184pub fn prepare(&self) -> Result {185// SAFETY: By the type invariants, self.as_raw() is a valid argument for186// [`clk_prepare`].187to_result(unsafe { bindings::clk_prepare(self.as_raw()) })188}189190/// Unprepare the clock.191///192/// Equivalent to the kernel's [`clk_unprepare`] API.193///194/// [`clk_unprepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_unprepare195#[inline]196pub fn unprepare(&self) {197// SAFETY: By the type invariants, self.as_raw() is a valid argument for198// [`clk_unprepare`].199unsafe { bindings::clk_unprepare(self.as_raw()) };200}201202/// Prepare and enable the clock.203///204/// Equivalent to calling [`Clk::prepare`] followed by [`Clk::enable`].205#[inline]206pub fn prepare_enable(&self) -> Result {207// SAFETY: By the type invariants, self.as_raw() is a valid argument for208// [`clk_prepare_enable`].209to_result(unsafe { bindings::clk_prepare_enable(self.as_raw()) })210}211212/// Disable and unprepare the clock.213///214/// Equivalent to calling [`Clk::disable`] followed by [`Clk::unprepare`].215#[inline]216pub fn disable_unprepare(&self) {217// SAFETY: By the type invariants, self.as_raw() is a valid argument for218// [`clk_disable_unprepare`].219unsafe { bindings::clk_disable_unprepare(self.as_raw()) };220}221222/// Get clock's rate.223///224/// Equivalent to the kernel's [`clk_get_rate`] API.225///226/// [`clk_get_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_rate227#[inline]228pub fn rate(&self) -> Hertz {229// SAFETY: By the type invariants, self.as_raw() is a valid argument for230// [`clk_get_rate`].231Hertz(unsafe { bindings::clk_get_rate(self.as_raw()) })232}233234/// Set clock's rate.235///236/// Equivalent to the kernel's [`clk_set_rate`] API.237///238/// [`clk_set_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_set_rate239#[inline]240pub fn set_rate(&self, rate: Hertz) -> Result {241// SAFETY: By the type invariants, self.as_raw() is a valid argument for242// [`clk_set_rate`].243to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) })244}245}246247impl Drop for Clk {248fn drop(&mut self) {249// SAFETY: By the type invariants, self.as_raw() is a valid argument for [`clk_put`].250unsafe { bindings::clk_put(self.as_raw()) };251}252}253254/// A reference-counted optional clock.255///256/// A lightweight wrapper around an optional [`Clk`]. An [`OptionalClk`] represents a [`Clk`]257/// that a driver can function without but may improve performance or enable additional258/// features when available.259///260/// # Invariants261///262/// An [`OptionalClk`] instance encapsulates a [`Clk`] with either a valid [`struct clk`] or263/// `NULL` pointer.264///265/// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the266/// allocation remains valid for the lifetime of the [`OptionalClk`].267///268/// # Examples269///270/// The following example demonstrates how to obtain and configure an optional clock for a271/// device. The code functions correctly whether or not the clock is available.272///273/// ```274/// use kernel::c_str;275/// use kernel::clk::{OptionalClk, Hertz};276/// use kernel::device::Device;277/// use kernel::error::Result;278///279/// fn configure_clk(dev: &Device) -> Result {280/// let clk = OptionalClk::get(dev, Some(c_str!("apb_clk")))?;281///282/// clk.prepare_enable()?;283///284/// let expected_rate = Hertz::from_ghz(1);285///286/// if clk.rate() != expected_rate {287/// clk.set_rate(expected_rate)?;288/// }289///290/// clk.disable_unprepare();291/// Ok(())292/// }293/// ```294///295/// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html296pub struct OptionalClk(Clk);297298impl OptionalClk {299/// Gets [`OptionalClk`] corresponding to a [`Device`] and a connection id.300///301/// Equivalent to the kernel's [`clk_get_optional`] API.302///303/// [`clk_get_optional`]:304/// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional305pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {306let con_id = name.map_or(ptr::null(), |n| n.as_ptr());307308// SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer.309//310// INVARIANT: The reference-count is decremented when [`OptionalClk`] goes out of311// scope.312Ok(Self(Clk(from_err_ptr(unsafe {313bindings::clk_get_optional(dev.as_raw(), con_id)314})?)))315}316}317318// Make [`OptionalClk`] behave like [`Clk`].319impl Deref for OptionalClk {320type Target = Clk;321322fn deref(&self) -> &Clk {323&self.0324}325}326}327328#[cfg(CONFIG_COMMON_CLK)]329pub use common_clk::*;330331332