Re: [PATCH v4] rust: regulator: add a bare minimum regulator abstraction
From: Miguel Ojeda
Date: Mon Jun 09 2025 - 12:23:58 EST
On Mon, Jun 9, 2025 at 5:34 PM Daniel Almeida
<daniel.almeida@xxxxxxxxxxxxx> 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.
For future versions, or at apply time, please see the attached diff
for some documentation fixes (mostly) -- please check with
`--ignore-space-change`, since some indentation fixes can hide other
changes.
Most should be self-explanatory, but if there is something that you
think should not be done, please let me know of course.
Thanks!
Cheers,
Miguel
diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs
index 338fc653c32b..0baf763a098e 100644
--- a/rust/kernel/regulator.rs
+++ b/rust/kernel/regulator.rs
@@ -13,7 +13,7 @@
//! 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")
+//! See [Voltage and current regulator API](https://docs.kernel.org/driver-api/regulator.html)
//! for more information.
use crate::{
@@ -72,6 +72,7 @@ impl IsEnabled for Dynamic {}
pub struct Error<State: RegulatorState + 'static> {
/// The error that occurred.
pub error: kernel::error::Error,
+
/// The regulator that caused the error, so that the operation may be retried.
pub regulator: Regulator<State>,
}
@@ -80,7 +81,7 @@ pub struct Error<State: RegulatorState + 'static> {
///
/// # Examples
///
-/// Enabling a regulator:
+/// ## 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
@@ -95,37 +96,40 @@ pub struct Error<State: RegulatorState + 'static> {
/// # 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::<(), Error>(())
+/// // 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()`:
@@ -136,40 +140,44 @@ pub struct Error<State: RegulatorState + 'static> {
/// # 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::<(), Error>(())
+/// // 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:
+/// ## 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::<(), Error>(())
+/// // 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>`:
+/// ## 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
@@ -182,33 +190,33 @@ pub struct Error<State: RegulatorState + 'static> {
/// # 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, data: &mut PrivateData) -> 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()?;
-///
-/// Ok(PrivateData {
-/// regulator,
-/// })
+/// // 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()?;
+///
+/// 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()?;
+/// // Decrease the `enabled` reference count.
+/// data.regulator.disable()?;
+///
/// Ok(())
/// }
///
@@ -221,13 +229,14 @@ pub struct Error<State: RegulatorState + 'static> {
/// // to `enable()` and `disabled()` are balanced before this point.
/// Ok(())
/// }
-///
-///
/// ```
+///
/// # Invariants
///
/// - `inner` is a non-null wrapper over a pointer to a `struct
-/// regulator` obtained from [`regulator_get()`](https://docs.kernel.org/driver-api/regulator.html#c.regulator_get).
+/// regulator` obtained from [`regulator_get()`].
+///
+/// [`regulator_get()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_get
pub struct Regulator<State = Dynamic>
where
State: RegulatorState + 'static,
@@ -379,7 +388,7 @@ fn drop(&mut self) {
/// A voltage in microvolts.
///
/// The explicit type is used to avoid confusion with other multiples of the
-/// volt, which can be desastrous.
+/// volt, which can be disastrous.
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Microvolt(pub i32);