From: Boris Brezillon <boris.brezillon@collabora.com>
To: "Gary Guo" <gary@garyguo.net>
Cc: "Daniel Almeida" <daniel.almeida@collabora.com>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Viresh Kumar" <viresh.kumar@linaro.org>,
"Danilo Krummrich" <dakr@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Drew Fustini" <fustini@kernel.org>,
"Guo Ren" <guoren@kernel.org>, "Fu Wei" <wefu@redhat.com>,
"Uwe Kleine-König" <ukleinek@kernel.org>,
"Michael Turquette" <mturquette@baylibre.com>,
"Stephen Boyd" <sboyd@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org,
linux-pwm@vger.kernel.org, linux-clk@vger.kernel.org,
rust-for-linux@vger.kernel.org
Subject: Re: [PATCH v3 1/3] rust: clk: use the type-state pattern
Date: Mon, 2 Feb 2026 17:10:38 +0100 [thread overview]
Message-ID: <20260202171038.10e51e18@fedora> (raw)
In-Reply-To: <DFSMRQFIYQPO.1A38Y84XZ1GZO@garyguo.net>
On Mon, 19 Jan 2026 14:20:43 +0000
"Gary Guo" <gary@garyguo.net> wrote:
> On Wed Jan 7, 2026 at 3:09 PM GMT, Daniel Almeida wrote:
> > The current Clk abstraction can still be improved on the following issues:
> >
> > a) It only keeps track of a count to clk_get(), which means that users have
> > to manually call disable() and unprepare(), or a variation of those, like
> > disable_unprepare().
> >
> > b) It allows repeated calls to prepare() or enable(), but it keeps no track
> > of how often these were called, i.e., it's currently legal to write the
> > following:
> >
> > clk.prepare();
> > clk.prepare();
> > clk.enable();
> > clk.enable();
> >
> > And nothing gets undone on drop().
> >
> > c) It adds a OptionalClk type that is probably not needed. There is no
> > "struct optional_clk" in C and we should probably not add one.
> >
> > d) It does not let a user express the state of the clk through the
> > type system. For example, there is currently no way to encode that a Clk is
> > enabled via the type system alone.
> >
> > In light of the Regulator abstraction that was recently merged, switch this
> > abstraction to use the type-state pattern instead. It solves both a) and b)
> > by establishing a number of states and the valid ways to transition between
> > them. It also automatically undoes any call to clk_get(), clk_prepare() and
> > clk_enable() as applicable on drop(), so users do not have to do anything
> > special before Clk goes out of scope.
> >
> > It solves c) by removing the OptionalClk type, which is now simply encoded
> > as a Clk whose inner pointer is NULL.
> >
> > It solves d) by directly encoding the state of the Clk into the type, e.g.:
> > Clk<Enabled> is now known to be a Clk that is enabled.
> >
> > The INVARIANTS section for Clk is expanded to highlight the relationship
> > between the states and the respective reference counts that are owned by
> > each of them.
> >
> > The examples are expanded to highlight how a user can transition between
> > states, as well as highlight some of the shortcuts built into the API.
> >
> > The current implementation is also more flexible, in the sense that it
> > allows for more states to be added in the future. This lets us implement
> > different strategies for handling clocks, including one that mimics the
> > current API, allowing for multiple calls to prepare() and enable().
> >
> > The users (cpufreq.rs/ rcpufreq_dt.rs) were updated by this patch (and not
> > a separate one) to reflect the new changes. This is needed, because
> > otherwise this patch would break the build.
> >
> > Link: https://crates.io/crates/sealed [1]
> > Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> > ---
> > drivers/cpufreq/rcpufreq_dt.rs | 2 +-
> > drivers/gpu/drm/tyr/driver.rs | 31 +---
> > drivers/pwm/pwm_th1520.rs | 17 +-
> > rust/kernel/clk.rs | 399 +++++++++++++++++++++++++++--------------
> > rust/kernel/cpufreq.rs | 8 +-
> > 5 files changed, 281 insertions(+), 176 deletions(-)
> >
> > diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
> > index 31e07f0279db..f1bd7d71ed54 100644
> > --- a/drivers/cpufreq/rcpufreq_dt.rs
> > +++ b/drivers/cpufreq/rcpufreq_dt.rs
> > @@ -41,7 +41,7 @@ struct CPUFreqDTDevice {
> > freq_table: opp::FreqTable,
> > _mask: CpumaskVar,
> > _token: Option<opp::ConfigToken>,
> > - _clk: Clk,
> > + _clk: Clk<kernel::clk::Unprepared>,
> > }
> >
> > #[derive(Default)]
> > diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
> > index 09711fb7fe0b..5692def25621 100644
> > --- a/drivers/gpu/drm/tyr/driver.rs
> > +++ b/drivers/gpu/drm/tyr/driver.rs
> > @@ -2,7 +2,7 @@
> >
> > use kernel::c_str;
> > use kernel::clk::Clk;
> > -use kernel::clk::OptionalClk;
> > +use kernel::clk::Enabled;
> > use kernel::device::Bound;
> > use kernel::device::Core;
> > use kernel::device::Device;
> > @@ -37,7 +37,7 @@ pub(crate) struct TyrDriver {
> > device: ARef<TyrDevice>,
> > }
> >
> > -#[pin_data(PinnedDrop)]
> > +#[pin_data]
> > pub(crate) struct TyrData {
> > pub(crate) pdev: ARef<platform::Device>,
> >
> > @@ -92,13 +92,9 @@ fn probe(
> > pdev: &platform::Device<Core>,
> > _info: Option<&Self::IdInfo>,
> > ) -> impl PinInit<Self, Error> {
> > - let core_clk = Clk::get(pdev.as_ref(), Some(c_str!("core")))?;
> > - let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("stacks")))?;
> > - let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("coregroup")))?;
> > -
> > - core_clk.prepare_enable()?;
> > - stacks_clk.prepare_enable()?;
> > - coregroup_clk.prepare_enable()?;
> > + let core_clk = Clk::<Enabled>::get(pdev.as_ref(), Some(c_str!("core")))?;
>
> Ah, more turbofish.. I'd really want to avoid them if possible.
>
> Any disadvantage on just ask the user to chain `.get().prepare_enable()?`? This
> way it is also clear that some action is performed.
I've just disc
>
> Alternatively, I think function names that mimick C API is also fine, e.g.
> `Clk::get_enabled`.
>
> > + let stacks_clk = Clk::<Enabled>::get_optional(pdev.as_ref(), Some(c_str!("stacks")))?;
> > + let coregroup_clk = Clk::<Enabled>::get_optional(pdev.as_ref(), Some(c_str!("coregroup")))?;
> >
> > let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("mali"))?;
> > let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("sram"))?;
> > @@ -145,17 +141,6 @@ impl PinnedDrop for TyrDriver {
> > fn drop(self: Pin<&mut Self>) {}
> > }
> >
> > -#[pinned_drop]
> > -impl PinnedDrop for TyrData {
> > - fn drop(self: Pin<&mut Self>) {
> > - // TODO: the type-state pattern for Clks will fix this.
> > - let clks = self.clks.lock();
> > - clks.core.disable_unprepare();
> > - clks.stacks.disable_unprepare();
> > - clks.coregroup.disable_unprepare();
> > - }
> > -}
> > -
> > // We need to retain the name "panthor" to achieve drop-in compatibility with
> > // the C driver in the userspace stack.
> > const INFO: drm::DriverInfo = drm::DriverInfo {
> > @@ -181,9 +166,9 @@ impl drm::Driver for TyrDriver {
> >
> > #[pin_data]
> > struct Clocks {
> > - core: Clk,
> > - stacks: OptionalClk,
> > - coregroup: OptionalClk,
> > + core: Clk<Enabled>,
> > + stacks: Clk<Enabled>,
> > + coregroup: Clk<Enabled>,
> > }
> >
> > #[pin_data]
> > diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
> > index 043dc4dbc623..f4d03b988533 100644
> > --- a/drivers/pwm/pwm_th1520.rs
> > +++ b/drivers/pwm/pwm_th1520.rs
> > @@ -23,7 +23,7 @@
> > use core::ops::Deref;
> > use kernel::{
> > c_str,
> > - clk::Clk,
> > + clk::{Clk, Enabled},
> > device::{Bound, Core, Device},
> > devres,
> > io::mem::IoMem,
> > @@ -90,11 +90,11 @@ struct Th1520WfHw {
> > }
> >
> > /// The driver's private data struct. It holds all necessary devres managed resources.
> > -#[pin_data(PinnedDrop)]
> > +#[pin_data]
> > struct Th1520PwmDriverData {
> > #[pin]
> > iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>,
> > - clk: Clk,
> > + clk: Clk<Enabled>,
> > }
> >
> > impl pwm::PwmOps for Th1520PwmDriverData {
> > @@ -299,13 +299,6 @@ fn write_waveform(
> > }
> > }
> >
> > -#[pinned_drop]
> > -impl PinnedDrop for Th1520PwmDriverData {
> > - fn drop(self: Pin<&mut Self>) {
> > - self.clk.disable_unprepare();
> > - }
> > -}
> > -
> > struct Th1520PwmPlatformDriver;
> >
> > kernel::of_device_table!(
> > @@ -326,9 +319,7 @@ fn probe(
> > let dev = pdev.as_ref();
> > let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
> >
> > - let clk = Clk::get(dev, None)?;
> > -
> > - clk.prepare_enable()?;
> > + let clk = Clk::<Enabled>::get(dev, None)?;
> >
> > // TODO: Get exclusive ownership of the clock to prevent rate changes.
> > // The Rust equivalent of `clk_rate_exclusive_get()` is not yet available.
> > diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
> > index d192fbd97861..6323b40dc7ba 100644
> > --- a/rust/kernel/clk.rs
> > +++ b/rust/kernel/clk.rs
> > @@ -80,17 +80,78 @@ fn from(freq: Hertz) -> Self {
> > mod common_clk {
> > use super::Hertz;
> > use crate::{
> > - device::Device,
> > + device::{Bound, Device},
> > error::{from_err_ptr, to_result, Result},
> > prelude::*,
> > };
> >
> > - use core::{ops::Deref, ptr};
> > + use core::{marker::PhantomData, mem::ManuallyDrop, ptr};
> > +
> > + mod private {
> > + pub trait Sealed {}
> > +
> > + impl Sealed for super::Unprepared {}
> > + impl Sealed for super::Prepared {}
> > + impl Sealed for super::Enabled {}
> > + }
>
> I guess it's time for me to work on a `#[sealed]` macro...
>
> > +
> > + /// A trait representing the different states that a [`Clk`] can be in.
> > + pub trait ClkState: private::Sealed {
> > + /// Whether the clock should be disabled when dropped.
> > + const DISABLE_ON_DROP: bool;
> > +
> > + /// Whether the clock should be unprepared when dropped.
> > + const UNPREPARE_ON_DROP: bool;
> > + }
> > +
> > + /// A state where the [`Clk`] is not prepared and not enabled.
>
> Do we want to make it explicit that it's "not known to be prepared or
> enabled"?
>
> > + pub struct Unprepared;
> > +
> > + /// A state where the [`Clk`] is prepared but not enabled.
> > + pub struct Prepared;
> > +
> > + /// A state where the [`Clk`] is both prepared and enabled.
> > + pub struct Enabled;
> > +
> > + impl ClkState for Unprepared {
> > + const DISABLE_ON_DROP: bool = false;
> > + const UNPREPARE_ON_DROP: bool = false;
> > + }
> > +
> > + impl ClkState for Prepared {
> > + const DISABLE_ON_DROP: bool = false;
> > + const UNPREPARE_ON_DROP: bool = true;
> > + }
> > +
> > + impl ClkState for Enabled {
> > + const DISABLE_ON_DROP: bool = true;
> > + const UNPREPARE_ON_DROP: bool = true;
> > + }
> > +
> > + /// An error that can occur when trying to convert a [`Clk`] between states.
> > + pub struct Error<State: ClkState> {
> > + /// The error that occurred.
> > + pub error: kernel::error::Error,
> > +
> > + /// The [`Clk`] that caused the error, so that the operation may be
> > + /// retried.
> > + pub clk: Clk<State>,
> > + }
>
> I wonder if it makes sense to add a general `ErrorWith` type for errors that
> carries error code + data.
>
> Best,
> Gary
WARNING: multiple messages have this Message-ID (diff)
From: Boris Brezillon <boris.brezillon@collabora.com>
To: "Gary Guo" <gary@garyguo.net>
Cc: "Daniel Almeida" <daniel.almeida@collabora.com>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Viresh Kumar" <viresh.kumar@linaro.org>,
"Danilo Krummrich" <dakr@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Drew Fustini" <fustini@kernel.org>,
"Guo Ren" <guoren@kernel.org>, "Fu Wei" <wefu@redhat.com>,
"Uwe Kleine-König" <ukleinek@kernel.org>,
"Michael Turquette" <mturquette@baylibre.com>,
"Stephen Boyd" <sboyd@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
dri-devel@lists.freedesktop.org, linux-riscv@lists.infradead.org,
linux-pwm@vger.kernel.org, linux-clk@vger.kernel.org,
rust-for-linux@vger.kernel.org
Subject: Re: [PATCH v3 1/3] rust: clk: use the type-state pattern
Date: Mon, 2 Feb 2026 17:10:38 +0100 [thread overview]
Message-ID: <20260202171038.10e51e18@fedora> (raw)
In-Reply-To: <DFSMRQFIYQPO.1A38Y84XZ1GZO@garyguo.net>
On Mon, 19 Jan 2026 14:20:43 +0000
"Gary Guo" <gary@garyguo.net> wrote:
> On Wed Jan 7, 2026 at 3:09 PM GMT, Daniel Almeida wrote:
> > The current Clk abstraction can still be improved on the following issues:
> >
> > a) It only keeps track of a count to clk_get(), which means that users have
> > to manually call disable() and unprepare(), or a variation of those, like
> > disable_unprepare().
> >
> > b) It allows repeated calls to prepare() or enable(), but it keeps no track
> > of how often these were called, i.e., it's currently legal to write the
> > following:
> >
> > clk.prepare();
> > clk.prepare();
> > clk.enable();
> > clk.enable();
> >
> > And nothing gets undone on drop().
> >
> > c) It adds a OptionalClk type that is probably not needed. There is no
> > "struct optional_clk" in C and we should probably not add one.
> >
> > d) It does not let a user express the state of the clk through the
> > type system. For example, there is currently no way to encode that a Clk is
> > enabled via the type system alone.
> >
> > In light of the Regulator abstraction that was recently merged, switch this
> > abstraction to use the type-state pattern instead. It solves both a) and b)
> > by establishing a number of states and the valid ways to transition between
> > them. It also automatically undoes any call to clk_get(), clk_prepare() and
> > clk_enable() as applicable on drop(), so users do not have to do anything
> > special before Clk goes out of scope.
> >
> > It solves c) by removing the OptionalClk type, which is now simply encoded
> > as a Clk whose inner pointer is NULL.
> >
> > It solves d) by directly encoding the state of the Clk into the type, e.g.:
> > Clk<Enabled> is now known to be a Clk that is enabled.
> >
> > The INVARIANTS section for Clk is expanded to highlight the relationship
> > between the states and the respective reference counts that are owned by
> > each of them.
> >
> > The examples are expanded to highlight how a user can transition between
> > states, as well as highlight some of the shortcuts built into the API.
> >
> > The current implementation is also more flexible, in the sense that it
> > allows for more states to be added in the future. This lets us implement
> > different strategies for handling clocks, including one that mimics the
> > current API, allowing for multiple calls to prepare() and enable().
> >
> > The users (cpufreq.rs/ rcpufreq_dt.rs) were updated by this patch (and not
> > a separate one) to reflect the new changes. This is needed, because
> > otherwise this patch would break the build.
> >
> > Link: https://crates.io/crates/sealed [1]
> > Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
> > ---
> > drivers/cpufreq/rcpufreq_dt.rs | 2 +-
> > drivers/gpu/drm/tyr/driver.rs | 31 +---
> > drivers/pwm/pwm_th1520.rs | 17 +-
> > rust/kernel/clk.rs | 399 +++++++++++++++++++++++++++--------------
> > rust/kernel/cpufreq.rs | 8 +-
> > 5 files changed, 281 insertions(+), 176 deletions(-)
> >
> > diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
> > index 31e07f0279db..f1bd7d71ed54 100644
> > --- a/drivers/cpufreq/rcpufreq_dt.rs
> > +++ b/drivers/cpufreq/rcpufreq_dt.rs
> > @@ -41,7 +41,7 @@ struct CPUFreqDTDevice {
> > freq_table: opp::FreqTable,
> > _mask: CpumaskVar,
> > _token: Option<opp::ConfigToken>,
> > - _clk: Clk,
> > + _clk: Clk<kernel::clk::Unprepared>,
> > }
> >
> > #[derive(Default)]
> > diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
> > index 09711fb7fe0b..5692def25621 100644
> > --- a/drivers/gpu/drm/tyr/driver.rs
> > +++ b/drivers/gpu/drm/tyr/driver.rs
> > @@ -2,7 +2,7 @@
> >
> > use kernel::c_str;
> > use kernel::clk::Clk;
> > -use kernel::clk::OptionalClk;
> > +use kernel::clk::Enabled;
> > use kernel::device::Bound;
> > use kernel::device::Core;
> > use kernel::device::Device;
> > @@ -37,7 +37,7 @@ pub(crate) struct TyrDriver {
> > device: ARef<TyrDevice>,
> > }
> >
> > -#[pin_data(PinnedDrop)]
> > +#[pin_data]
> > pub(crate) struct TyrData {
> > pub(crate) pdev: ARef<platform::Device>,
> >
> > @@ -92,13 +92,9 @@ fn probe(
> > pdev: &platform::Device<Core>,
> > _info: Option<&Self::IdInfo>,
> > ) -> impl PinInit<Self, Error> {
> > - let core_clk = Clk::get(pdev.as_ref(), Some(c_str!("core")))?;
> > - let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("stacks")))?;
> > - let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("coregroup")))?;
> > -
> > - core_clk.prepare_enable()?;
> > - stacks_clk.prepare_enable()?;
> > - coregroup_clk.prepare_enable()?;
> > + let core_clk = Clk::<Enabled>::get(pdev.as_ref(), Some(c_str!("core")))?;
>
> Ah, more turbofish.. I'd really want to avoid them if possible.
>
> Any disadvantage on just ask the user to chain `.get().prepare_enable()?`? This
> way it is also clear that some action is performed.
I've just disc
>
> Alternatively, I think function names that mimick C API is also fine, e.g.
> `Clk::get_enabled`.
>
> > + let stacks_clk = Clk::<Enabled>::get_optional(pdev.as_ref(), Some(c_str!("stacks")))?;
> > + let coregroup_clk = Clk::<Enabled>::get_optional(pdev.as_ref(), Some(c_str!("coregroup")))?;
> >
> > let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("mali"))?;
> > let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("sram"))?;
> > @@ -145,17 +141,6 @@ impl PinnedDrop for TyrDriver {
> > fn drop(self: Pin<&mut Self>) {}
> > }
> >
> > -#[pinned_drop]
> > -impl PinnedDrop for TyrData {
> > - fn drop(self: Pin<&mut Self>) {
> > - // TODO: the type-state pattern for Clks will fix this.
> > - let clks = self.clks.lock();
> > - clks.core.disable_unprepare();
> > - clks.stacks.disable_unprepare();
> > - clks.coregroup.disable_unprepare();
> > - }
> > -}
> > -
> > // We need to retain the name "panthor" to achieve drop-in compatibility with
> > // the C driver in the userspace stack.
> > const INFO: drm::DriverInfo = drm::DriverInfo {
> > @@ -181,9 +166,9 @@ impl drm::Driver for TyrDriver {
> >
> > #[pin_data]
> > struct Clocks {
> > - core: Clk,
> > - stacks: OptionalClk,
> > - coregroup: OptionalClk,
> > + core: Clk<Enabled>,
> > + stacks: Clk<Enabled>,
> > + coregroup: Clk<Enabled>,
> > }
> >
> > #[pin_data]
> > diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
> > index 043dc4dbc623..f4d03b988533 100644
> > --- a/drivers/pwm/pwm_th1520.rs
> > +++ b/drivers/pwm/pwm_th1520.rs
> > @@ -23,7 +23,7 @@
> > use core::ops::Deref;
> > use kernel::{
> > c_str,
> > - clk::Clk,
> > + clk::{Clk, Enabled},
> > device::{Bound, Core, Device},
> > devres,
> > io::mem::IoMem,
> > @@ -90,11 +90,11 @@ struct Th1520WfHw {
> > }
> >
> > /// The driver's private data struct. It holds all necessary devres managed resources.
> > -#[pin_data(PinnedDrop)]
> > +#[pin_data]
> > struct Th1520PwmDriverData {
> > #[pin]
> > iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>,
> > - clk: Clk,
> > + clk: Clk<Enabled>,
> > }
> >
> > impl pwm::PwmOps for Th1520PwmDriverData {
> > @@ -299,13 +299,6 @@ fn write_waveform(
> > }
> > }
> >
> > -#[pinned_drop]
> > -impl PinnedDrop for Th1520PwmDriverData {
> > - fn drop(self: Pin<&mut Self>) {
> > - self.clk.disable_unprepare();
> > - }
> > -}
> > -
> > struct Th1520PwmPlatformDriver;
> >
> > kernel::of_device_table!(
> > @@ -326,9 +319,7 @@ fn probe(
> > let dev = pdev.as_ref();
> > let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
> >
> > - let clk = Clk::get(dev, None)?;
> > -
> > - clk.prepare_enable()?;
> > + let clk = Clk::<Enabled>::get(dev, None)?;
> >
> > // TODO: Get exclusive ownership of the clock to prevent rate changes.
> > // The Rust equivalent of `clk_rate_exclusive_get()` is not yet available.
> > diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
> > index d192fbd97861..6323b40dc7ba 100644
> > --- a/rust/kernel/clk.rs
> > +++ b/rust/kernel/clk.rs
> > @@ -80,17 +80,78 @@ fn from(freq: Hertz) -> Self {
> > mod common_clk {
> > use super::Hertz;
> > use crate::{
> > - device::Device,
> > + device::{Bound, Device},
> > error::{from_err_ptr, to_result, Result},
> > prelude::*,
> > };
> >
> > - use core::{ops::Deref, ptr};
> > + use core::{marker::PhantomData, mem::ManuallyDrop, ptr};
> > +
> > + mod private {
> > + pub trait Sealed {}
> > +
> > + impl Sealed for super::Unprepared {}
> > + impl Sealed for super::Prepared {}
> > + impl Sealed for super::Enabled {}
> > + }
>
> I guess it's time for me to work on a `#[sealed]` macro...
>
> > +
> > + /// A trait representing the different states that a [`Clk`] can be in.
> > + pub trait ClkState: private::Sealed {
> > + /// Whether the clock should be disabled when dropped.
> > + const DISABLE_ON_DROP: bool;
> > +
> > + /// Whether the clock should be unprepared when dropped.
> > + const UNPREPARE_ON_DROP: bool;
> > + }
> > +
> > + /// A state where the [`Clk`] is not prepared and not enabled.
>
> Do we want to make it explicit that it's "not known to be prepared or
> enabled"?
>
> > + pub struct Unprepared;
> > +
> > + /// A state where the [`Clk`] is prepared but not enabled.
> > + pub struct Prepared;
> > +
> > + /// A state where the [`Clk`] is both prepared and enabled.
> > + pub struct Enabled;
> > +
> > + impl ClkState for Unprepared {
> > + const DISABLE_ON_DROP: bool = false;
> > + const UNPREPARE_ON_DROP: bool = false;
> > + }
> > +
> > + impl ClkState for Prepared {
> > + const DISABLE_ON_DROP: bool = false;
> > + const UNPREPARE_ON_DROP: bool = true;
> > + }
> > +
> > + impl ClkState for Enabled {
> > + const DISABLE_ON_DROP: bool = true;
> > + const UNPREPARE_ON_DROP: bool = true;
> > + }
> > +
> > + /// An error that can occur when trying to convert a [`Clk`] between states.
> > + pub struct Error<State: ClkState> {
> > + /// The error that occurred.
> > + pub error: kernel::error::Error,
> > +
> > + /// The [`Clk`] that caused the error, so that the operation may be
> > + /// retried.
> > + pub clk: Clk<State>,
> > + }
>
> I wonder if it makes sense to add a general `ErrorWith` type for errors that
> carries error code + data.
>
> Best,
> Gary
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
next prev parent reply other threads:[~2026-02-02 16:10 UTC|newest]
Thread overview: 136+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-07 15:09 [PATCH v3 0/3] Clk improvements Daniel Almeida
2026-01-07 15:09 ` Daniel Almeida
2026-01-07 15:09 ` [PATCH v3 1/3] rust: clk: use the type-state pattern Daniel Almeida
2026-01-07 15:09 ` Daniel Almeida
2026-01-08 8:07 ` Maxime Ripard
2026-01-08 8:07 ` Maxime Ripard
2026-01-08 13:57 ` Miguel Ojeda
2026-01-08 13:57 ` Miguel Ojeda
2026-01-08 14:18 ` Daniel Almeida
2026-01-08 14:18 ` Daniel Almeida
2026-01-08 14:14 ` Daniel Almeida
2026-01-08 14:14 ` Daniel Almeida
2026-01-19 10:45 ` Maxime Ripard
2026-01-19 10:45 ` Maxime Ripard
2026-01-19 12:13 ` Daniel Almeida
2026-01-19 12:13 ` Daniel Almeida
2026-01-19 12:35 ` Alice Ryhl
2026-01-19 12:35 ` Alice Ryhl
2026-01-19 12:54 ` Daniel Almeida
2026-01-19 12:54 ` Daniel Almeida
2026-01-19 13:13 ` Danilo Krummrich
2026-01-19 13:13 ` Danilo Krummrich
2026-01-19 14:18 ` Maxime Ripard
2026-01-19 14:18 ` Maxime Ripard
2026-01-19 14:37 ` Danilo Krummrich
2026-01-19 14:37 ` Danilo Krummrich
2026-01-22 13:44 ` Maxime Ripard
2026-01-22 13:44 ` Maxime Ripard
2026-01-23 0:29 ` Daniel Almeida
2026-01-23 0:29 ` Daniel Almeida
2026-02-04 9:15 ` Maxime Ripard
2026-02-04 9:15 ` Maxime Ripard
2026-02-04 12:43 ` Daniel Almeida
2026-02-04 12:43 ` Daniel Almeida
2026-02-04 14:34 ` Maxime Ripard
2026-02-04 14:34 ` Maxime Ripard
2026-02-09 9:50 ` Boris Brezillon
2026-02-09 9:50 ` Boris Brezillon
2026-02-11 16:37 ` Maxime Ripard
2026-02-11 16:37 ` Maxime Ripard
2026-02-11 16:47 ` Danilo Krummrich
2026-02-11 16:47 ` Danilo Krummrich
2026-02-12 7:59 ` Maxime Ripard
2026-02-12 7:59 ` Maxime Ripard
2026-02-12 8:52 ` Alice Ryhl
2026-02-12 8:52 ` Alice Ryhl
2026-02-12 9:23 ` Danilo Krummrich
2026-02-12 9:23 ` Danilo Krummrich
2026-02-12 14:01 ` Danilo Krummrich
2026-02-12 14:01 ` Danilo Krummrich
2026-02-12 16:50 ` Maxime Ripard
2026-02-12 16:50 ` Maxime Ripard
2026-02-12 11:45 ` Miguel Ojeda
2026-02-12 11:45 ` Miguel Ojeda
2026-02-12 8:16 ` Alice Ryhl
2026-02-12 8:16 ` Alice Ryhl
2026-02-12 13:38 ` Maxime Ripard
2026-02-12 13:38 ` Maxime Ripard
2026-02-12 14:02 ` Alice Ryhl
2026-02-12 14:02 ` Alice Ryhl
2026-02-12 16:48 ` Maxime Ripard
2026-02-12 16:48 ` Maxime Ripard
2026-01-23 10:25 ` Danilo Krummrich
2026-01-23 10:25 ` Danilo Krummrich
2026-01-19 12:57 ` Gary Guo
2026-01-19 12:57 ` Gary Guo
2026-01-19 14:27 ` Maxime Ripard
2026-01-19 14:27 ` Maxime Ripard
2026-02-03 10:39 ` Boris Brezillon
2026-02-03 10:39 ` Boris Brezillon
2026-02-03 11:26 ` Boris Brezillon
2026-02-03 11:26 ` Boris Brezillon
2026-02-03 14:53 ` Boris Brezillon
2026-02-03 14:53 ` Boris Brezillon
2026-02-03 13:33 ` Daniel Almeida
2026-02-03 13:33 ` Daniel Almeida
2026-02-03 13:42 ` Gary Guo
2026-02-03 13:42 ` Gary Guo
2026-02-03 13:55 ` Daniel Almeida
2026-02-03 13:55 ` Daniel Almeida
2026-02-03 14:33 ` Boris Brezillon
2026-02-03 14:33 ` Boris Brezillon
2026-02-03 14:08 ` Boris Brezillon
2026-02-03 14:08 ` Boris Brezillon
2026-02-03 16:28 ` Daniel Almeida
2026-02-03 16:28 ` Daniel Almeida
2026-02-03 16:55 ` Boris Brezillon
2026-02-03 16:55 ` Boris Brezillon
2026-02-03 16:59 ` Gary Guo
2026-02-03 16:59 ` Gary Guo
2026-02-03 19:26 ` Daniel Almeida
2026-02-03 19:26 ` Daniel Almeida
2026-02-03 19:43 ` Boris Brezillon
2026-02-03 19:43 ` Boris Brezillon
2026-02-03 20:36 ` Gary Guo
2026-02-03 20:36 ` Gary Guo
2026-02-04 8:11 ` Boris Brezillon
2026-02-04 8:11 ` Boris Brezillon
2026-02-04 9:18 ` Maxime Ripard
2026-02-04 9:18 ` Maxime Ripard
2026-01-19 14:26 ` Gary Guo
2026-01-19 14:26 ` Gary Guo
2026-01-19 15:44 ` Daniel Almeida
2026-01-19 15:44 ` Daniel Almeida
2026-01-19 14:20 ` Gary Guo
2026-01-19 14:20 ` Gary Guo
2026-01-19 15:22 ` Miguel Ojeda
2026-01-19 15:22 ` Miguel Ojeda
2026-01-19 15:36 ` Gary Guo
2026-01-19 15:36 ` Gary Guo
2026-01-19 15:46 ` Miguel Ojeda
2026-01-19 15:46 ` Miguel Ojeda
2026-01-19 16:10 ` Gary Guo
2026-01-19 16:10 ` Gary Guo
2026-02-02 16:10 ` Boris Brezillon [this message]
2026-02-02 16:10 ` Boris Brezillon
2026-02-03 9:09 ` Boris Brezillon
2026-02-03 9:09 ` Boris Brezillon
2026-02-03 9:47 ` Boris Brezillon
2026-02-03 9:47 ` Boris Brezillon
2026-02-03 13:37 ` Daniel Almeida
2026-02-03 13:37 ` Daniel Almeida
2026-02-03 14:18 ` Boris Brezillon
2026-02-03 14:18 ` Boris Brezillon
2026-02-03 9:17 ` Boris Brezillon
2026-02-03 9:17 ` Boris Brezillon
2026-02-03 13:35 ` Daniel Almeida
2026-02-03 13:35 ` Daniel Almeida
2026-01-07 15:09 ` [PATCH v3 2/3] rust: clk: add devres-managed clks Daniel Almeida
2026-01-07 15:09 ` Daniel Almeida
2026-01-19 14:33 ` Gary Guo
2026-01-19 14:33 ` Gary Guo
2026-01-07 15:09 ` [PATCH v3 3/3] rust: clk: use 'kernel vertical style' for imports Daniel Almeida
2026-01-07 15:09 ` Daniel Almeida
2026-01-08 7:53 ` Maxime Ripard
2026-01-08 7:53 ` Maxime Ripard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260202171038.10e51e18@fedora \
--to=boris.brezillon@collabora.com \
--cc=a.hindborg@kernel.org \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=fustini@kernel.org \
--cc=gary@garyguo.net \
--cc=guoren@kernel.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=lossin@kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=mturquette@baylibre.com \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sboyd@kernel.org \
--cc=simona@ffwll.ch \
--cc=tmgross@umich.edu \
--cc=tzimmermann@suse.de \
--cc=ukleinek@kernel.org \
--cc=viresh.kumar@linaro.org \
--cc=wefu@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.