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 const KHZ_TO_HZ: c_ulong = 1_000; 34 const MHZ_TO_HZ: c_ulong = 1_000_000; 35 const GHZ_TO_HZ: c_ulong = 1_000_000_000; 36 37 /// Create a new instance from kilohertz (kHz) 38 pub const fn from_khz(khz: c_ulong) -> Self { 39 Self(khz * Self::KHZ_TO_HZ) 40 } 41 42 /// Create a new instance from megahertz (MHz) 43 pub const fn from_mhz(mhz: c_ulong) -> Self { 44 Self(mhz * Self::MHZ_TO_HZ) 45 } 46 47 /// Create a new instance from gigahertz (GHz) 48 pub const fn from_ghz(ghz: c_ulong) -> Self { 49 Self(ghz * Self::GHZ_TO_HZ) 50 } 51 52 /// Get the frequency in hertz 53 pub const fn as_hz(&self) -> c_ulong { 54 self.0 55 } 56 57 /// Get the frequency in kilohertz 58 pub const fn as_khz(&self) -> c_ulong { 59 self.0 / Self::KHZ_TO_HZ 60 } 61 62 /// Get the frequency in megahertz 63 pub const fn as_mhz(&self) -> c_ulong { 64 self.0 / Self::MHZ_TO_HZ 65 } 66 67 /// Get the frequency in gigahertz 68 pub const fn as_ghz(&self) -> c_ulong { 69 self.0 / Self::GHZ_TO_HZ 70 } 71 } 72 73 impl From<Hertz> for c_ulong { 74 fn from(freq: Hertz) -> Self { 75 freq.0 76 } 77 } 78 79 #[cfg(CONFIG_COMMON_CLK)] 80 mod common_clk { 81 use super::Hertz; 82 use crate::{ 83 device::Device, 84 error::{from_err_ptr, to_result, Result}, 85 prelude::*, 86 }; 87 88 use core::{ops::Deref, ptr}; 89 90 /// A reference-counted clock. 91 /// 92 /// Rust abstraction for the C [`struct clk`]. 93 /// 94 /// # Invariants 95 /// 96 /// A [`Clk`] instance holds either a pointer to a valid [`struct clk`] created by the C 97 /// portion of the kernel or a `NULL` pointer. 98 /// 99 /// Instances of this type are reference-counted. Calling [`Clk::get`] ensures that the 100 /// allocation remains valid for the lifetime of the [`Clk`]. 101 /// 102 /// # Examples 103 /// 104 /// The following example demonstrates how to obtain and configure a clock for a device. 105 /// 106 /// ``` 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"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.html 128 #[repr(transparent)] 129 pub struct Clk(*mut bindings::clk); 130 131 // SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called. 132 unsafe impl Send for Clk {} 133 134 // SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the 135 // methods are synchronized internally. 136 unsafe impl Sync for Clk {} 137 138 impl Clk { 139 /// Gets [`Clk`] corresponding to a [`Device`] and a connection id. 140 /// 141 /// Equivalent to the kernel's [`clk_get`] API. 142 /// 143 /// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get 144 pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> { 145 let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr()); 146 147 // SAFETY: It is safe to call [`clk_get`] for a valid device pointer. 148 // 149 // INVARIANT: The reference-count is decremented when [`Clk`] goes out of scope. 150 Ok(Self(from_err_ptr(unsafe { 151 bindings::clk_get(dev.as_raw(), con_id) 152 })?)) 153 } 154 155 /// Obtain the raw [`struct clk`] pointer. 156 #[inline] 157 pub fn as_raw(&self) -> *mut bindings::clk { 158 self.0 159 } 160 161 /// Enable the clock. 162 /// 163 /// Equivalent to the kernel's [`clk_enable`] API. 164 /// 165 /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable 166 #[inline] 167 pub fn enable(&self) -> Result { 168 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 169 // [`clk_enable`]. 170 to_result(unsafe { bindings::clk_enable(self.as_raw()) }) 171 } 172 173 /// Disable the clock. 174 /// 175 /// Equivalent to the kernel's [`clk_disable`] API. 176 /// 177 /// [`clk_disable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_disable 178 #[inline] 179 pub fn disable(&self) { 180 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 181 // [`clk_disable`]. 182 unsafe { bindings::clk_disable(self.as_raw()) }; 183 } 184 185 /// Prepare the clock. 186 /// 187 /// Equivalent to the kernel's [`clk_prepare`] API. 188 /// 189 /// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_prepare 190 #[inline] 191 pub fn prepare(&self) -> Result { 192 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 193 // [`clk_prepare`]. 194 to_result(unsafe { bindings::clk_prepare(self.as_raw()) }) 195 } 196 197 /// Unprepare the clock. 198 /// 199 /// Equivalent to the kernel's [`clk_unprepare`] API. 200 /// 201 /// [`clk_unprepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_unprepare 202 #[inline] 203 pub fn unprepare(&self) { 204 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 205 // [`clk_unprepare`]. 206 unsafe { bindings::clk_unprepare(self.as_raw()) }; 207 } 208 209 /// Prepare and enable the clock. 210 /// 211 /// Equivalent to calling [`Clk::prepare`] followed by [`Clk::enable`]. 212 #[inline] 213 pub fn prepare_enable(&self) -> Result { 214 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 215 // [`clk_prepare_enable`]. 216 to_result(unsafe { bindings::clk_prepare_enable(self.as_raw()) }) 217 } 218 219 /// Disable and unprepare the clock. 220 /// 221 /// Equivalent to calling [`Clk::disable`] followed by [`Clk::unprepare`]. 222 #[inline] 223 pub fn disable_unprepare(&self) { 224 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 225 // [`clk_disable_unprepare`]. 226 unsafe { bindings::clk_disable_unprepare(self.as_raw()) }; 227 } 228 229 /// Get clock's rate. 230 /// 231 /// Equivalent to the kernel's [`clk_get_rate`] API. 232 /// 233 /// [`clk_get_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_rate 234 #[inline] 235 pub fn rate(&self) -> Hertz { 236 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 237 // [`clk_get_rate`]. 238 Hertz(unsafe { bindings::clk_get_rate(self.as_raw()) }) 239 } 240 241 /// Set clock's rate. 242 /// 243 /// Equivalent to the kernel's [`clk_set_rate`] API. 244 /// 245 /// [`clk_set_rate`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_set_rate 246 #[inline] 247 pub fn set_rate(&self, rate: Hertz) -> Result { 248 // SAFETY: By the type invariants, self.as_raw() is a valid argument for 249 // [`clk_set_rate`]. 250 to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) }) 251 } 252 } 253 254 impl Drop for Clk { 255 fn drop(&mut self) { 256 // SAFETY: By the type invariants, self.as_raw() is a valid argument for [`clk_put`]. 257 unsafe { bindings::clk_put(self.as_raw()) }; 258 } 259 } 260 261 /// A reference-counted optional clock. 262 /// 263 /// A lightweight wrapper around an optional [`Clk`]. An [`OptionalClk`] represents a [`Clk`] 264 /// that a driver can function without but may improve performance or enable additional 265 /// features when available. 266 /// 267 /// # Invariants 268 /// 269 /// An [`OptionalClk`] instance encapsulates a [`Clk`] with either a valid [`struct clk`] or 270 /// `NULL` pointer. 271 /// 272 /// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the 273 /// allocation remains valid for the lifetime of the [`OptionalClk`]. 274 /// 275 /// # Examples 276 /// 277 /// The following example demonstrates how to obtain and configure an optional clock for a 278 /// device. The code functions correctly whether or not the clock is available. 279 /// 280 /// ``` 281 /// use kernel::clk::{OptionalClk, Hertz}; 282 /// use kernel::device::Device; 283 /// use kernel::error::Result; 284 /// 285 /// fn configure_clk(dev: &Device) -> Result { 286 /// let clk = OptionalClk::get(dev, Some(c"apb_clk"))?; 287 /// 288 /// clk.prepare_enable()?; 289 /// 290 /// let expected_rate = Hertz::from_ghz(1); 291 /// 292 /// if clk.rate() != expected_rate { 293 /// clk.set_rate(expected_rate)?; 294 /// } 295 /// 296 /// clk.disable_unprepare(); 297 /// Ok(()) 298 /// } 299 /// ``` 300 /// 301 /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html 302 pub struct OptionalClk(Clk); 303 304 impl OptionalClk { 305 /// Gets [`OptionalClk`] corresponding to a [`Device`] and a connection id. 306 /// 307 /// Equivalent to the kernel's [`clk_get_optional`] API. 308 /// 309 /// [`clk_get_optional`]: 310 /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional 311 pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> { 312 let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr()); 313 314 // SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer. 315 // 316 // INVARIANT: The reference-count is decremented when [`OptionalClk`] goes out of 317 // scope. 318 Ok(Self(Clk(from_err_ptr(unsafe { 319 bindings::clk_get_optional(dev.as_raw(), con_id) 320 })?))) 321 } 322 } 323 324 // Make [`OptionalClk`] behave like [`Clk`]. 325 impl Deref for OptionalClk { 326 type Target = Clk; 327 328 fn deref(&self) -> &Clk { 329 &self.0 330 } 331 } 332 } 333 334 #[cfg(CONFIG_COMMON_CLK)] 335 pub use common_clk::*; 336