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) from_khz(khz: c_ulong) -> Self34 pub fn from_khz(khz: c_ulong) -> Self { 35 Self(khz * 1_000) 36 } 37 38 /// Create a new instance from megahertz (MHz) from_mhz(mhz: c_ulong) -> Self39 pub fn from_mhz(mhz: c_ulong) -> Self { 40 Self(mhz * 1_000_000) 41 } 42 43 /// Create a new instance from gigahertz (GHz) from_ghz(ghz: c_ulong) -> Self44 pub fn from_ghz(ghz: c_ulong) -> Self { 45 Self(ghz * 1_000_000_000) 46 } 47 48 /// Get the frequency in hertz as_hz(&self) -> c_ulong49 pub fn as_hz(&self) -> c_ulong { 50 self.0 51 } 52 53 /// Get the frequency in kilohertz as_khz(&self) -> c_ulong54 pub fn as_khz(&self) -> c_ulong { 55 self.0 / 1_000 56 } 57 58 /// Get the frequency in megahertz as_mhz(&self) -> c_ulong59 pub fn as_mhz(&self) -> c_ulong { 60 self.0 / 1_000_000 61 } 62 63 /// Get the frequency in gigahertz as_ghz(&self) -> c_ulong64 pub fn as_ghz(&self) -> c_ulong { 65 self.0 / 1_000_000_000 66 } 67 } 68 69 impl From<Hertz> for c_ulong { from(freq: Hertz) -> Self70 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 get(dev: &Device, name: Option<&CStr>) -> Result<Self>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] as_raw(&self) -> *mut bindings::clk151 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] enable(&self) -> Result161 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] disable(&self)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] prepare(&self) -> Result185 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] unprepare(&self)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] prepare_enable(&self) -> Result207 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] disable_unprepare(&self)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] rate(&self) -> Hertz229 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] set_rate(&self, rate: Hertz) -> Result241 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 { drop(&mut self)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 get(dev: &Device, name: Option<&CStr>) -> Result<Self>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 deref(&self) -> &Clk327 fn deref(&self) -> &Clk { 328 &self.0 329 } 330 } 331 } 332 333 #[cfg(CONFIG_COMMON_CLK)] 334 pub use common_clk::*; 335