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