From: "Alexandre Courbot" <acourbot@nvidia.com>
To: "Daniel Almeida" <daniel.almeida@collabora.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Boris Brezillon" <boris.brezillon@collabora.com>,
"Sebastian Reichel" <sebastian.reichel@collabora.com>,
"Liam Girdwood" <lgirdwood@gmail.com>,
"Mark Brown" <broonie@kernel.org>,
"Benno Lossin" <lossin@kernel.org>
Cc: <linux-kernel@vger.kernel.org>, <rust-for-linux@vger.kernel.org>
Subject: Re: [PATCH v7 1/2] rust: regulator: add a bare minimum regulator abstraction
Date: Mon, 07 Jul 2025 14:39:12 +0900 [thread overview]
Message-ID: <DB5KXNL9KKJ4.AAINEGNOD5JK@nvidia.com> (raw)
In-Reply-To: <20250704-topics-tyr-regulator-v7-1-77bfca2e22dc@collabora.com>
Hi Daniel,
On Sat Jul 5, 2025 at 3:43 AM JST, Daniel Almeida wrote:
> Add a bare minimum regulator abstraction to be used by Rust drivers.
> This abstraction adds a small subset of the regulator API, which is
> thought to be sufficient for the drivers we have now.
>
> Regulators provide the power needed by many hardware blocks and thus are
> likely to be needed by a lot of drivers.
>
> It was tested on rk3588, where it was used to power up the "mali"
> regulator in order to power up the GPU.
>
> Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
I think this looks great.
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
A few comments inline.
> ---
> rust/bindings/bindings_helper.h | 1 +
> rust/kernel/lib.rs | 1 +
> rust/kernel/regulator.rs | 403 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 405 insertions(+)
>
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 8cbb660e2ec218021d16e6e0144acf6f4d7cca13..2d51f9d056091e34120b4ade9ff7cc4a7f53e111 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -65,6 +65,7 @@
> #include <linux/poll.h>
> #include <linux/property.h>
> #include <linux/refcount.h>
> +#include <linux/regulator/consumer.h>
> #include <linux/sched.h>
> #include <linux/security.h>
> #include <linux/slab.h>
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 6b4774b2b1c37f4da1866e993be6230bc6715841..5e4cd8c5e6ff1c4af52a5b1be4c4c32b5104e233 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -100,6 +100,7 @@
> pub mod prelude;
> pub mod print;
> pub mod rbtree;
> +pub mod regulator;
> pub mod revocable;
> pub mod security;
> pub mod seq_file;
> diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..56f3a91469549551f54c7b4c7ec67aa941acd572
> --- /dev/null
> +++ b/rust/kernel/regulator.rs
> @@ -0,0 +1,403 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Regulator abstractions, providing a standard kernel interface to control
> +//! voltage and current regulators.
> +//!
> +//! The intention is to allow systems to dynamically control regulator power
> +//! output in order to save power and prolong battery life. This applies to both
> +//! voltage regulators (where voltage output is controllable) and current sinks
> +//! (where current limit is controllable).
> +//!
> +//! C header: [`include/linux/regulator/consumer.h`](srctree/include/linux/regulator/consumer.h)
> +//!
> +//! Regulators are modeled in Rust with a collection of states. Each state may
> +//! enforce a given invariant, and they may convert between each other where applicable.
> +//!
> +//! See [Voltage and current regulator API](https://docs.kernel.org/driver-api/regulator.html)
> +//! for more information.
> +
> +use crate::{
> + bindings,
> + device::Device,
> + error::{from_err_ptr, to_result, Result},
> + prelude::*,
> +};
> +
> +use core::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull};
> +
> +mod private {
> + pub trait Sealed {}
> +
> + impl Sealed for super::Enabled {}
> + impl Sealed for super::Disabled {}
> + impl Sealed for super::Dynamic {}
> +}
> +
> +/// A trait representing the different states a [`Regulator`] can be in.
> +pub trait RegulatorState: private::Sealed + 'static {
> + /// Whether the regulator should be disabled when dropped.
> + const DISABLE_ON_DROP: bool;
> +}
> +
> +/// A state where the [`Regulator`] is known to be enabled.
For safety, let's maybe explicitly state that the enable reference held
by this state is released when it is dropped. The example below mentions
it, so I think we should do it here as well.
<snip>
> +/// A `struct regulator` abstraction.
> +///
> +/// # Examples
> +///
> +/// ## Enabling a regulator
> +///
> +/// This example uses [`Regulator<Enabled>`], which is suitable for drivers that
> +/// enable a regulator at probe time and leave them on until the device is
> +/// removed or otherwise shutdown.
> +///
> +/// These users can store [`Regulator<Enabled>`] directly in their driver's
> +/// private data struct.
> +///
> +/// ```
> +/// # use kernel::prelude::*;
> +/// # use kernel::c_str;
> +/// # use kernel::device::Device;
> +/// # use kernel::regulator::{Microvolt, Regulator, Disabled, Enabled};
> +/// fn enable(dev: &Device, min_uv: Microvolt, max_uv: Microvolt) -> Result {
> +/// // Obtain a reference to a (fictitious) regulator.
> +/// let regulator: Regulator<Disabled> = Regulator::<Disabled>::get(dev, c_str!("vcc"))?;
> +///
> +/// // The voltage can be set before enabling the regulator if needed, e.g.:
> +/// regulator.set_voltage(min_uv, max_uv)?;
> +///
> +/// // The same applies for `get_voltage()`, i.e.:
> +/// let voltage: Microvolt = regulator.get_voltage()?;
> +///
> +/// // Enables the regulator, consuming the previous value.
> +/// //
> +/// // From now on, the regulator is known to be enabled because of the type
> +/// // `Enabled`.
> +/// //
> +/// // If this operation fails, the `Error` will contain the regulator
> +/// // reference, so that the operation may be retried.
> +/// let regulator: Regulator<Enabled> =
> +/// regulator.try_into_enabled().map_err(|error| error.error)?;
> +///
> +/// // The voltage can also be set after enabling the regulator, e.g.:
> +/// regulator.set_voltage(min_uv, max_uv)?;
> +///
> +/// // The same applies for `get_voltage()`, i.e.:
> +/// let voltage: Microvolt = regulator.get_voltage()?;
> +///
> +/// // Dropping an enabled regulator will disable it. The refcount will be
> +/// // decremented.
> +/// drop(regulator);
> +///
> +/// // ...
> +///
> +/// Ok(())
> +/// }
> +/// ```
> +///
> +/// A more concise shortcut is available for enabling a regulator. This is
> +/// equivalent to `regulator_get_enable()`:
> +///
> +/// ```
> +/// # use kernel::prelude::*;
> +/// # use kernel::c_str;
> +/// # use kernel::device::Device;
> +/// # use kernel::regulator::{Microvolt, Regulator, Enabled};
> +/// fn enable(dev: &Device, min_uv: Microvolt, max_uv: Microvolt) -> Result {
> +/// // Obtain a reference to a (fictitious) regulator and enable it.
> +/// let regulator: Regulator<Enabled> = Regulator::<Enabled>::get(dev, c_str!("vcc"))?;
> +///
> +/// // Dropping an enabled regulator will disable it. The refcount will be
> +/// // decremented.
> +/// drop(regulator);
> +///
> +/// // ...
> +///
> +/// Ok(())
> +/// }
> +/// ```
> +///
> +/// ## Disabling a regulator
> +///
> +/// ```
> +/// # use kernel::prelude::*;
> +/// # use kernel::device::Device;
> +/// # use kernel::regulator::{Regulator, Enabled, Disabled};
> +/// fn disable(dev: &Device, regulator: Regulator<Enabled>) -> Result {
> +/// // We can also disable an enabled regulator without reliquinshing our
> +/// // refcount:
> +/// //
> +/// // If this operation fails, the `Error` will contain the regulator
> +/// // reference, so that the operation may be retried.
> +/// let regulator: Regulator<Disabled> =
> +/// regulator.try_into_disabled().map_err(|error| error.error)?;
> +///
> +/// // The refcount will be decremented when `regulator` is dropped.
> +/// drop(regulator);
> +///
> +/// // ...
> +///
> +/// Ok(())
> +/// }
> +/// ```
> +///
> +/// ## Using [`Regulator<Dynamic>`]
> +///
> +/// This example mimics the behavior of the C API, where the user is in
> +/// control of the enabled reference count. This is useful for drivers that
> +/// might call enable and disable to manage the `enable` reference count at
> +/// runtime, perhaps as a result of `open()` and `close()` calls or whatever
> +/// other driver-specific or subsystem-specific hooks.
> +///
> +/// ```
> +/// # use kernel::prelude::*;
> +/// # use kernel::c_str;
> +/// # use kernel::device::Device;
> +/// # use kernel::regulator::{Regulator, Dynamic};
> +/// struct PrivateData {
> +/// regulator: Regulator<Dynamic>,
> +/// }
> +///
> +/// // A fictictious probe function that obtains a regulator and sets it up.
> +/// fn probe(dev: &Device) -> Result<PrivateData> {
> +/// // Obtain a reference to a (fictitious) regulator.
> +/// let mut regulator = Regulator::<Dynamic>::get(dev, c_str!("vcc"))?;
> +///
> +/// // Enable the regulator. The type is still `Regulator<Dynamic>`.
> +/// regulator.enable()?;
If we enable the regulator at probe-time, then it is guaranteed to be
enabled for the time the device is bound - in that case, doesn't it turn
the `enable()` and `disable()` calls in `open` and `close` into no-ops?
I would remove this line as the `enable()` method is demonstrated in
`open()` anyway.
> +///
> +/// Ok(PrivateData { regulator })
> +/// }
> +///
> +/// // A fictictious function that indicates that the device is going to be used.
> +/// fn open(dev: &Device, data: &mut PrivateData) -> Result {
> +/// // Increase the `enabled` reference count.
> +/// data.regulator.enable()?;
> +///
> +/// Ok(())
> +/// }
> +///
> +/// fn close(dev: &Device, data: &mut PrivateData) -> Result {
> +/// // Decrease the `enabled` reference count.
> +/// data.regulator.disable()?;
> +///
> +/// Ok(())
> +/// }
> +///
> +/// fn remove(dev: &Device, data: PrivateData) -> Result {
> +/// // `PrivateData` is dropped here, which will drop the
> +/// // `Regulator<Dynamic>` in turn.
> +/// //
> +/// // The reference that was obtained by `regulator_get()` will be
> +/// // released, but it is up to the user to make sure that the number of calls
> +/// // to `enable()` and `disabled()` are balanced before this point.
Ironically the `enable()` line in `probe()` is not balanced here. :)
> +/// Ok(())
> +/// }
> +/// ```
These examples are great!
<snip>
> +/// A voltage in microvolts.
> +///
> +/// The explicit type is used to avoid confusion with other multiples of the
> +/// volt, which can be disastrous.
> +#[repr(transparent)]
> +#[derive(Copy, Clone, PartialEq, Eq)]
> +pub struct Microvolt(pub i32);
I still think a `Voltage` type is preferable and more idiomatic here as
the unit would be made explicit by the methods anyway, but your call.
next prev parent reply other threads:[~2025-07-07 5:39 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-04 18:43 [PATCH v7 0/2] Add a bare-minimum Regulator abstraction Daniel Almeida
2025-07-04 18:43 ` [PATCH v7 1/2] rust: regulator: add a bare minimum regulator abstraction Daniel Almeida
2025-07-06 0:39 ` kernel test robot
2025-07-07 16:23 ` Daniel Almeida
2025-07-07 5:39 ` Alexandre Courbot [this message]
2025-07-04 18:43 ` [PATCH v7 2/2] MAINAINTERS: add regulator.rs to the regulator API entry Daniel Almeida
2025-07-07 5:39 ` Alexandre Courbot
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=DB5KXNL9KKJ4.AAINEGNOD5JK@nvidia.com \
--to=acourbot@nvidia.com \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=boris.brezillon@collabora.com \
--cc=broonie@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=gary@garyguo.net \
--cc=lgirdwood@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sebastian.reichel@collabora.com \
--cc=tmgross@umich.edu \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®