OptionalClk wraps a Clk whose pointer may be NULL and derefs to it. There is no struct optional_clk in C. clk_get_optional() returns a struct clk pointer that is NULL when the clock has no producer, and the clk functions that Clk wraps accept NULL. The type invariant of Clk already allows a NULL pointer, so the wrapper is not needed.
Add Clk::get_optional() and remove OptionalClk. Convert tyr, its only user. Signed-off-by: Daniel Almeida <[email protected]> --- drivers/gpu/drm/tyr/driver.rs | 13 +++--- rust/kernel/clk.rs | 98 +++++++++---------------------------------- 2 files changed, 25 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index bfb0ba19caff..c382a26904ee 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -1,10 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 or MIT use kernel::{ - clk::{ - Clk, - OptionalClk, // - }, + clk::Clk, device::{ Bound, Core, @@ -117,8 +114,8 @@ fn probe<'bound>( _info: Option<&'bound Self::IdInfo>, ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; - let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; - let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; + let stacks_clk = Clk::get_optional(pdev.as_ref(), Some(c"stacks"))?; + let coregroup_clk = Clk::get_optional(pdev.as_ref(), Some(c"coregroup"))?; core_clk.prepare_enable()?; stacks_clk.prepare_enable()?; @@ -219,8 +216,8 @@ impl drm::Driver for TyrDrmDriver { struct Clocks { core: Clk, - stacks: OptionalClk, - coregroup: OptionalClk, + stacks: Clk, + coregroup: Clk, } impl Drop for Clocks { diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index c73fe7c57251..1de2484df8cf 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -103,10 +103,7 @@ mod common_clk { prelude::*, // }; - use core::{ - ops::Deref, - ptr, // - }; + use core::ptr; /// A reference-counted clock. /// @@ -175,6 +172,25 @@ pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> { })?)) } + /// Behaves the same as [`Self::get`], except when there is no clock + /// producer. In this case, instead of returning [`ENOENT`], it returns + /// a dummy [`Clk`]. + /// + /// Equivalent to the kernel's [`clk_get_optional`] API. + /// + /// [`clk_get_optional`]: + /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional + pub fn get_optional(dev: &Device, name: Option<&CStr>) -> Result<Self> { + let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr()); + + // SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer. + // + // INVARIANT: The reference-count is decremented when [`Clk`] goes out of scope. + Ok(Self(from_err_ptr(unsafe { + bindings::clk_get_optional(dev.as_raw(), con_id) + })?)) + } + /// Obtain the raw [`struct clk`] pointer. #[inline] pub fn as_raw(&self) -> *mut bindings::clk { @@ -280,80 +296,6 @@ fn drop(&mut self) { unsafe { bindings::clk_put(self.as_raw()) }; } } - - /// A reference-counted optional clock. - /// - /// A lightweight wrapper around an optional [`Clk`]. An [`OptionalClk`] represents a [`Clk`] - /// that a driver can function without but may improve performance or enable additional - /// features when available. - /// - /// # Invariants - /// - /// An [`OptionalClk`] instance encapsulates a [`Clk`] with either a valid [`struct clk`] or - /// `NULL` pointer. - /// - /// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the - /// allocation remains valid for the lifetime of the [`OptionalClk`]. - /// - /// # Examples - /// - /// The following example demonstrates how to obtain and configure an optional clock for a - /// device. The code functions correctly whether or not the clock is available. - /// - /// ``` - /// use kernel::clk::{ - /// Hertz, - /// OptionalClk, - /// }; - /// use kernel::device::Device; - /// - /// fn configure_clk(dev: &Device) -> Result { - /// let clk = OptionalClk::get(dev, Some(c"apb_clk"))?; - /// - /// clk.prepare_enable()?; - /// - /// let expected_rate = Hertz::from_ghz(1); - /// - /// if clk.rate() != expected_rate { - /// clk.set_rate(expected_rate)?; - /// } - /// - /// clk.disable_unprepare(); - /// Ok(()) - /// } - /// ``` - /// - /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html - pub struct OptionalClk(Clk); - - impl OptionalClk { - /// Gets [`OptionalClk`] corresponding to a [`Device`] and a connection id. - /// - /// Equivalent to the kernel's [`clk_get_optional`] API. - /// - /// [`clk_get_optional`]: - /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional - pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> { - let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr()); - - // SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer. - // - // INVARIANT: The reference-count is decremented when [`OptionalClk`] goes out of - // scope. - Ok(Self(Clk(from_err_ptr(unsafe { - bindings::clk_get_optional(dev.as_raw(), con_id) - })?))) - } - } - - // Make [`OptionalClk`] behave like [`Clk`]. - impl Deref for OptionalClk { - type Target = Clk; - - fn deref(&self) -> &Clk { - &self.0 - } - } } #[cfg(CONFIG_COMMON_CLK)] -- 2.56.0
