From a2801affa7103862d549050401a9f53b3365fca4 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Wed, 11 Jun 2025 12:29:00 +0200 Subject: rust: device: Create FwNode abstraction for accessing device properties Accessing device properties is currently done via methods on `Device` itself, using bindings to device_property_* functions. This is sufficient for the existing method property_present. However, it's not sufficient for other device properties we want to access. For example, iterating over child nodes of a device will yield a fwnode_handle. That's not a device, so it wouldn't be possible to read the properties of that child node. Thus, we need an abstraction over fwnode_handle and methods for reading its properties. Add a struct FwNode which abstracts over the C struct fwnode_handle. Implement its reference counting analogous to other Rust abstractions over reference-counted C structs. Subsequent patches will add functionality to access FwNode and read properties with it. Tested-by: Dirk Behme Signed-off-by: Remo Senekowitsch Link: https://lore.kernel.org/r/20250611102908.212514-2-remo@buenzli.dev [ Add temporary #[expect(dead_code)] to avoid a warning. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/helpers/helpers.c | 1 + 1 file changed, 1 insertion(+) (limited to 'rust/helpers/helpers.c') diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 0f1b5d115985..ed00695af971 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -30,6 +30,7 @@ #include "platform.c" #include "pci.c" #include "pid_namespace.c" +#include "property.c" #include "rbtree.c" #include "rcu.c" #include "refcount.c" -- cgit v1.2.3 From 1b7bbd5975279a1cf8d907fbc719f350031194c2 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 2 May 2025 09:45:24 +0900 Subject: rust: time: Avoid 64-bit integer division on 32-bit architectures Avoid 64-bit integer division that 32-bit architectures don't implement generally. This uses ktime_to_us() and ktime_to_ms() instead. The time abstraction needs i64 / u32 division so C's div_s64() can be used but ktime_to_us() and ktime_to_ms() provide a simpler solution for this time abstraction problem on 32-bit architectures. 32-bit ARM is the only 32-bit architecture currently supported by Rust. Using the cfg attribute, only 32-bit architectures will call ktime_to_us() and ktime_to_ms(), while the other 64-bit architectures will continue to use the current code as-is to avoid the overhead. One downside of calling the C's functions is that the as_micros/millis methods can no longer be const fn. We stick with the simpler approach unless there's a compelling need for a const fn. Suggested-by: Arnd Bergmann Suggested-by: Boqun Feng Signed-off-by: FUJITA Tomonori Reviewed-by: Andreas Hindborg Link: https://lore.kernel.org/r/20250502004524.230553-1-fujita.tomonori@gmail.com Signed-off-by: Andreas Hindborg --- rust/helpers/helpers.c | 1 + rust/helpers/time.c | 13 +++++++++++++ rust/kernel/time.rs | 26 ++++++++++++++++++++++---- 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 rust/helpers/time.c (limited to 'rust/helpers/helpers.c') diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 16fa9bca5949..1a05bb0dd420 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -40,6 +40,7 @@ #include "spinlock.c" #include "sync.c" #include "task.c" +#include "time.c" #include "uaccess.c" #include "vmalloc.c" #include "wait.c" diff --git a/rust/helpers/time.c b/rust/helpers/time.c new file mode 100644 index 000000000000..3d31473bce08 --- /dev/null +++ b/rust/helpers/time.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +s64 rust_helper_ktime_to_us(const ktime_t kt) +{ + return ktime_to_us(kt); +} + +s64 rust_helper_ktime_to_ms(const ktime_t kt) +{ + return ktime_to_ms(kt); +} diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs index a8089a98da9e..b0a8f3c0ba49 100644 --- a/rust/kernel/time.rs +++ b/rust/kernel/time.rs @@ -228,13 +228,31 @@ impl Delta { /// Return the smallest number of microseconds greater than or equal /// to the value in the [`Delta`]. #[inline] - pub const fn as_micros_ceil(self) -> i64 { - self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC + pub fn as_micros_ceil(self) -> i64 { + #[cfg(CONFIG_64BIT)] + { + self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC + } + + #[cfg(not(CONFIG_64BIT))] + // SAFETY: It is always safe to call `ktime_to_us()` with any value. + unsafe { + bindings::ktime_to_us(self.as_nanos().saturating_add(NSEC_PER_USEC - 1)) + } } /// Return the number of milliseconds in the [`Delta`]. #[inline] - pub const fn as_millis(self) -> i64 { - self.as_nanos() / NSEC_PER_MSEC + pub fn as_millis(self) -> i64 { + #[cfg(CONFIG_64BIT)] + { + self.as_nanos() / NSEC_PER_MSEC + } + + #[cfg(not(CONFIG_64BIT))] + // SAFETY: It is always safe to call `ktime_to_ms()` with any value. + unsafe { + bindings::ktime_to_ms(self.as_nanos()) + } } } -- cgit v1.2.3 From 56a789f776f24e6b132ec00d4c27672ed4e2ec57 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Fri, 20 Jun 2025 16:15:04 +0100 Subject: rust: device: implement FwNode::is_of_node() Implement FwNode::is_of_node() in order to check whether a FwNode instance is embedded in a struct device_node. Reviewed-by: Rob Herring (Arm) Signed-off-by: Igor Korotin Link: https://lore.kernel.org/r/20250620151504.278766-1-igor.korotin.linux@gmail.com Signed-off-by: Danilo Krummrich --- MAINTAINERS | 1 + rust/helpers/helpers.c | 1 + rust/helpers/of.c | 8 ++++++++ rust/kernel/device/property.rs | 7 +++++++ 4 files changed, 17 insertions(+) create mode 100644 rust/helpers/of.c (limited to 'rust/helpers/helpers.c') diff --git a/MAINTAINERS b/MAINTAINERS index 68d2a32759ec..ac68531befed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18580,6 +18580,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git F: Documentation/ABI/testing/sysfs-firmware-ofw F: drivers/of/ F: include/linux/of*.h +F: rust/helpers/of.c F: rust/kernel/of.rs F: scripts/dtc/ F: tools/testing/selftests/dt/ diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 393ad201befb..0b09bd0e3561 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -28,6 +28,7 @@ #include "kunit.c" #include "mm.c" #include "mutex.c" +#include "of.c" #include "page.c" #include "platform.c" #include "pci.c" diff --git a/rust/helpers/of.c b/rust/helpers/of.c new file mode 100644 index 000000000000..86b51167c913 --- /dev/null +++ b/rust/helpers/of.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +bool rust_helper_is_of_node(const struct fwnode_handle *fwnode) +{ + return is_of_node(fwnode); +} diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs index 2f6f3ef17db7..49ee12a906db 100644 --- a/rust/kernel/device/property.rs +++ b/rust/kernel/device/property.rs @@ -61,6 +61,13 @@ impl FwNode { self.0.get() } + /// Returns `true` if `&self` is an OF node, `false` otherwise. + pub fn is_of_node(&self) -> bool { + // SAFETY: The type invariant of `Self` guarantees that `self.as_raw() is a pointer to a + // valid `struct fwnode_handle`. + unsafe { bindings::is_of_node(self.as_raw()) } + } + /// Returns an object that implements [`Display`](core::fmt::Display) for /// printing the name of a node. /// -- cgit v1.2.3 From de747bd023c09b5b7f3bf5c952d7b1da77a9caaa Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 23 Jun 2025 13:57:27 +0000 Subject: poll: rust: allow poll_table ptrs to be null It's possible for a poll_table to be null. This can happen if an end-user just wants to know if a resource has events right now without registering a waiter for when events become available. Furthermore, these null pointers should be handled transparently by the API, so we should not change `from_ptr` to return an `Option`. Thus, change `PollTable` to wrap a raw pointer rather than use a reference so that you can pass null. Comments mentioning `struct poll_table` are changed to just `poll_table` since `poll_table` is a typedef. (It's a typedef because it's supposed to be opaque.) Reviewed-by: Benno Lossin Signed-off-by: Alice Ryhl --- rust/helpers/helpers.c | 1 + rust/helpers/poll.c | 10 +++++++ rust/kernel/sync/poll.rs | 68 ++++++++++++++++++------------------------------ 3 files changed, 37 insertions(+), 42 deletions(-) create mode 100644 rust/helpers/poll.c (limited to 'rust/helpers/helpers.c') diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 0f1b5d115985..ff65073fe3a5 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -30,6 +30,7 @@ #include "platform.c" #include "pci.c" #include "pid_namespace.c" +#include "poll.c" #include "rbtree.c" #include "rcu.c" #include "refcount.c" diff --git a/rust/helpers/poll.c b/rust/helpers/poll.c new file mode 100644 index 000000000000..7e5b1751c2d5 --- /dev/null +++ b/rust/helpers/poll.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +void rust_helper_poll_wait(struct file *filp, wait_queue_head_t *wait_address, + poll_table *p) +{ + poll_wait(filp, wait_address, p); +} diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs index d7e6e59e124b..69f1368a2151 100644 --- a/rust/kernel/sync/poll.rs +++ b/rust/kernel/sync/poll.rs @@ -9,9 +9,8 @@ use crate::{ fs::File, prelude::*, sync::{CondVar, LockClassKey}, - types::Opaque, }; -use core::ops::Deref; +use core::{marker::PhantomData, ops::Deref}; /// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class. #[macro_export] @@ -23,58 +22,43 @@ macro_rules! new_poll_condvar { }; } -/// Wraps the kernel's `struct poll_table`. +/// Wraps the kernel's `poll_table`. /// /// # Invariants /// -/// This struct contains a valid `struct poll_table`. -/// -/// For a `struct poll_table` to be valid, its `_qproc` function must follow the safety -/// requirements of `_qproc` functions: -/// -/// * The `_qproc` function is given permission to enqueue a waiter to the provided `poll_table` -/// during the call. Once the waiter is removed and an rcu grace period has passed, it must no -/// longer access the `wait_queue_head`. +/// The pointer must be null or reference a valid `poll_table`. #[repr(transparent)] -pub struct PollTable(Opaque); +pub struct PollTable<'a> { + table: *mut bindings::poll_table, + _lifetime: PhantomData<&'a bindings::poll_table>, +} -impl PollTable { - /// Creates a reference to a [`PollTable`] from a valid pointer. +impl<'a> PollTable<'a> { + /// Creates a [`PollTable`] from a valid pointer. /// /// # Safety /// - /// The caller must ensure that for the duration of `'a`, the pointer will point at a valid poll - /// table (as defined in the type invariants). - /// - /// The caller must also ensure that the `poll_table` is only accessed via the returned - /// reference for the duration of `'a`. - pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable { - // SAFETY: The safety requirements guarantee the validity of the dereference, while the - // `PollTable` type being transparent makes the cast ok. - unsafe { &mut *ptr.cast() } - } - - fn get_qproc(&self) -> bindings::poll_queue_proc { - let ptr = self.0.get(); - // SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc` - // field is not modified concurrently with this call since we have an immutable reference. - unsafe { (*ptr)._qproc } + /// The pointer must be null or reference a valid `poll_table` for the duration of `'a`. + pub unsafe fn from_raw(table: *mut bindings::poll_table) -> Self { + // INVARIANTS: The safety requirements are the same as the struct invariants. + PollTable { + table, + _lifetime: PhantomData, + } } /// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified /// using the condition variable. - pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) { - if let Some(qproc) = self.get_qproc() { - // SAFETY: The pointers to `file` and `self` need to be valid for the duration of this - // call to `qproc`, which they are because they are references. - // - // The `cv.wait_queue_head` pointer must be valid until an rcu grace period after the - // waiter is removed. The `PollCondVar` is pinned, so before `cv.wait_queue_head` can - // be destroyed, the destructor must run. That destructor first removes all waiters, - // and then waits for an rcu grace period. Therefore, `cv.wait_queue_head` is valid for - // long enough. - unsafe { qproc(file.as_ptr() as _, cv.wait_queue_head.get(), self.0.get()) }; - } + pub fn register_wait(&self, file: &File, cv: &PollCondVar) { + // SAFETY: + // * `file.as_ptr()` references a valid file for the duration of this call. + // * `self.table` is null or references a valid poll_table for the duration of this call. + // * Since `PollCondVar` is pinned, its destructor is guaranteed to run before the memory + // containing `cv.wait_queue_head` is invalidated. Since the destructor clears all + // waiters and then waits for an rcu grace period, it's guaranteed that + // `cv.wait_queue_head` remains valid for at least an rcu grace period after the removal + // of the last waiter. + unsafe { bindings::poll_wait(file.as_ptr(), cv.wait_queue_head.get(), self.table) } } } -- cgit v1.2.3 From 8ffb945647f8740e2eab81ace8c87f9734c85f95 Mon Sep 17 00:00:00 2001 From: Krishna Ketan Rai Date: Sun, 29 Jun 2025 20:55:32 +0530 Subject: rust: helpers: sort includes alphabetically The helper includes should be sorted alphabetically as indicated by the comment at the top of the file, but they were not. Sort them properly. Suggested-by: Alice Ryhl Link: https://github.com/Rust-for-Linux/linux/issues/1174 Signed-off-by: Krishna Ketan Rai Link: https://lore.kernel.org/r/20250629152533.889-1-prafulrai522@gmail.com Signed-off-by: Miguel Ojeda --- rust/helpers/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust/helpers/helpers.c') diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index b15b3cddad4e..d3867d09e356 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -29,9 +29,9 @@ #include "mm.c" #include "mutex.c" #include "page.c" -#include "platform.c" #include "pci.c" #include "pid_namespace.c" +#include "platform.c" #include "rbtree.c" #include "rcu.c" #include "refcount.c" -- cgit v1.2.3 From 9b614ceada7cb846de1a1c3bb0b29b0a2726ef45 Mon Sep 17 00:00:00 2001 From: Daniel Almeida Date: Mon, 14 Jul 2025 15:52:04 -0300 Subject: rust: regulator: add a bare minimum regulator abstraction 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. Reviewed-by: Alexandre Courbot Signed-off-by: Daniel Almeida Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20250714-topics-tyr-regulator2-v8-1-c7ab3955d524@collabora.com Signed-off-by: Mark Brown --- rust/bindings/bindings_helper.h | 1 + rust/helpers/helpers.c | 1 + rust/helpers/regulator.c | 43 +++++ rust/kernel/lib.rs | 1 + rust/kernel/regulator.rs | 418 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 464 insertions(+) create mode 100644 rust/helpers/regulator.c create mode 100644 rust/kernel/regulator.rs (limited to 'rust/helpers/helpers.c') diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 8cbb660e2ec2..2d51f9d05609 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index b15b3cddad4e..f1f26ba91d97 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -33,6 +33,7 @@ #include "pci.c" #include "pid_namespace.c" #include "rbtree.c" +#include "regulator.c" #include "rcu.c" #include "refcount.c" #include "security.c" diff --git a/rust/helpers/regulator.c b/rust/helpers/regulator.c new file mode 100644 index 000000000000..cd8b7ba648ee --- /dev/null +++ b/rust/helpers/regulator.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#ifndef CONFIG_REGULATOR + +void rust_helper_regulator_put(struct regulator *regulator) +{ + regulator_put(regulator); +} + +int rust_helper_regulator_set_voltage(struct regulator *regulator, int min_uV, + int max_uV) +{ + return regulator_set_voltage(regulator, min_uV, max_uV); +} + +int rust_helper_regulator_get_voltage(struct regulator *regulator) +{ + return regulator_get_voltage(regulator); +} + +struct regulator *rust_helper_regulator_get(struct device *dev, const char *id) +{ + return regulator_get(dev, id); +} + +int rust_helper_regulator_enable(struct regulator *regulator) +{ + return regulator_enable(regulator); +} + +int rust_helper_regulator_disable(struct regulator *regulator) +{ + return regulator_disable(regulator); +} + +int rust_helper_regulator_is_enabled(struct regulator *regulator) +{ + return regulator_is_enabled(regulator); +} + +#endif diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 6b4774b2b1c3..5e4cd8c5e6ff 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -100,6 +100,7 @@ pub mod platform; 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 000000000000..65f3a125348f --- /dev/null +++ b/rust/kernel/regulator.rs @@ -0,0 +1,418 @@ +// 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. +/// +/// The `enable` reference count held by this state is decremented when it is +/// dropped. +pub struct Enabled; + +/// A state where this [`Regulator`] handle has not specifically asked for the +/// underlying regulator to be enabled. This means that this reference does not +/// own an `enable` reference count, but the regulator may still be on. +pub struct Disabled; + +/// A state that models the C API. The [`Regulator`] can be either enabled or +/// disabled, and the user is in control of the reference count. This is also +/// the default state. +/// +/// Use [`Regulator::is_enabled`] to check the regulator's current state. +pub struct Dynamic; + +impl RegulatorState for Enabled { + const DISABLE_ON_DROP: bool = true; +} + +impl RegulatorState for Disabled { + const DISABLE_ON_DROP: bool = false; +} + +impl RegulatorState for Dynamic { + const DISABLE_ON_DROP: bool = false; +} + +/// A trait that abstracts the ability to check if a [`Regulator`] is enabled. +pub trait IsEnabled: RegulatorState {} +impl IsEnabled for Disabled {} +impl IsEnabled for Dynamic {} + +/// An error that can occur when trying to convert a [`Regulator`] between states. +pub struct Error { + /// 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, +} + +/// A `struct regulator` abstraction. +/// +/// # Examples +/// +/// ## Enabling a regulator +/// +/// This example uses [`Regulator`], 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`] directly in their driver's +/// private data struct. +/// +/// ``` +/// # use kernel::prelude::*; +/// # use kernel::c_str; +/// # use kernel::device::Device; +/// # use kernel::regulator::{Voltage, Regulator, Disabled, Enabled}; +/// fn enable(dev: &Device, min_voltage: Voltage, max_voltage: Voltage) -> Result { +/// // Obtain a reference to a (fictitious) regulator. +/// let regulator: Regulator = Regulator::::get(dev, c_str!("vcc"))?; +/// +/// // The voltage can be set before enabling the regulator if needed, e.g.: +/// regulator.set_voltage(min_voltage, max_voltage)?; +/// +/// // The same applies for `get_voltage()`, i.e.: +/// let voltage: Voltage = 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 = +/// 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_voltage, max_voltage)?; +/// +/// // The same applies for `get_voltage()`, i.e.: +/// let voltage: Voltage = 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::{Voltage, Regulator, Enabled}; +/// fn enable(dev: &Device) -> Result { +/// // Obtain a reference to a (fictitious) regulator and enable it. +/// let regulator: Regulator = Regulator::::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) -> 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 = +/// regulator.try_into_disabled().map_err(|error| error.error)?; +/// +/// // The refcount will be decremented when `regulator` is dropped. +/// drop(regulator); +/// +/// // ... +/// +/// Ok(()) +/// } +/// ``` +/// +/// ## Using [`Regulator`] +/// +/// 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, +/// } +/// +/// // A fictictious probe function that obtains a regulator and sets it up. +/// fn probe(dev: &Device) -> Result { +/// // Obtain a reference to a (fictitious) regulator. +/// let mut regulator = Regulator::::get(dev, c_str!("vcc"))?; +/// +/// 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` 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. +/// Ok(()) +/// } +/// ``` +/// +/// # Invariants +/// +/// - `inner` is a non-null wrapper over a pointer to a `struct +/// regulator` obtained from [`regulator_get()`]. +/// +/// [`regulator_get()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_get +pub struct Regulator +where + State: RegulatorState, +{ + inner: NonNull, + _phantom: PhantomData, +} + +impl Regulator { + /// Sets the voltage for the regulator. + /// + /// This can be used to ensure that the device powers up cleanly. + pub fn set_voltage(&self, min_voltage: Voltage, max_voltage: Voltage) -> Result { + // SAFETY: Safe as per the type invariants of `Regulator`. + to_result(unsafe { + bindings::regulator_set_voltage( + self.inner.as_ptr(), + min_voltage.as_microvolts(), + max_voltage.as_microvolts(), + ) + }) + } + + /// Gets the current voltage of the regulator. + pub fn get_voltage(&self) -> Result { + // SAFETY: Safe as per the type invariants of `Regulator`. + let voltage = unsafe { bindings::regulator_get_voltage(self.inner.as_ptr()) }; + if voltage < 0 { + Err(kernel::error::Error::from_errno(voltage)) + } else { + Ok(Voltage::from_microvolts(voltage)) + } + } + + fn get_internal(dev: &Device, name: &CStr) -> Result> { + // SAFETY: It is safe to call `regulator_get()`, on a device pointer + // received from the C code. + let inner = from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_ptr()) })?; + + // SAFETY: We can safely trust `inner` to be a pointer to a valid + // regulator if `ERR_PTR` was not returned. + let inner = unsafe { NonNull::new_unchecked(inner) }; + + Ok(Self { + inner, + _phantom: PhantomData, + }) + } + + fn enable_internal(&mut self) -> Result { + // SAFETY: Safe as per the type invariants of `Regulator`. + to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) }) + } + + fn disable_internal(&mut self) -> Result { + // SAFETY: Safe as per the type invariants of `Regulator`. + to_result(unsafe { bindings::regulator_disable(self.inner.as_ptr()) }) + } +} + +impl Regulator { + /// Obtains a [`Regulator`] instance from the system. + pub fn get(dev: &Device, name: &CStr) -> Result { + Regulator::get_internal(dev, name) + } + + /// Attempts to convert the regulator to an enabled state. + pub fn try_into_enabled(self) -> Result, Error> { + // We will be transferring the ownership of our `regulator_get()` count to + // `Regulator`. + let mut regulator = ManuallyDrop::new(self); + + regulator + .enable_internal() + .map(|()| Regulator { + inner: regulator.inner, + _phantom: PhantomData, + }) + .map_err(|error| Error { + error, + regulator: ManuallyDrop::into_inner(regulator), + }) + } +} + +impl Regulator { + /// Obtains a [`Regulator`] instance from the system and enables it. + /// + /// This is equivalent to calling `regulator_get_enable()` in the C API. + pub fn get(dev: &Device, name: &CStr) -> Result { + Regulator::::get_internal(dev, name)? + .try_into_enabled() + .map_err(|error| error.error) + } + + /// Attempts to convert the regulator to a disabled state. + pub fn try_into_disabled(self) -> Result, Error> { + // We will be transferring the ownership of our `regulator_get()` count + // to `Regulator`. + let mut regulator = ManuallyDrop::new(self); + + regulator + .disable_internal() + .map(|()| Regulator { + inner: regulator.inner, + _phantom: PhantomData, + }) + .map_err(|error| Error { + error, + regulator: ManuallyDrop::into_inner(regulator), + }) + } +} + +impl Regulator { + /// Obtains a [`Regulator`] instance from the system. The current state of + /// the regulator is unknown and it is up to the user to manage the enabled + /// reference count. + /// + /// This closely mimics the behavior of the C API and can be used to + /// dynamically manage the enabled reference count at runtime. + pub fn get(dev: &Device, name: &CStr) -> Result { + Regulator::get_internal(dev, name) + } + + /// Increases the `enabled` reference count. + pub fn enable(&mut self) -> Result { + self.enable_internal() + } + + /// Decreases the `enabled` reference count. + pub fn disable(&mut self) -> Result { + self.disable_internal() + } +} + +impl Regulator { + /// Checks if the regulator is enabled. + pub fn is_enabled(&self) -> bool { + // SAFETY: Safe as per the type invariants of `Regulator`. + unsafe { bindings::regulator_is_enabled(self.inner.as_ptr()) != 0 } + } +} + +impl Drop for Regulator { + fn drop(&mut self) { + if T::DISABLE_ON_DROP { + // SAFETY: By the type invariants, we know that `self` owns a + // reference on the enabled refcount, so it is safe to relinquish it + // now. + unsafe { bindings::regulator_disable(self.inner.as_ptr()) }; + } + // SAFETY: By the type invariants, we know that `self` owns a reference, + // so it is safe to relinquish it now. + unsafe { bindings::regulator_put(self.inner.as_ptr()) }; + } +} + +/// A voltage. +/// +/// This type represents a voltage value in microvolts. +#[repr(transparent)] +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Voltage(i32); + +impl Voltage { + /// Creates a new `Voltage` from a value in microvolts. + pub fn from_microvolts(uv: i32) -> Self { + Self(uv) + } + + /// Returns the value of the voltage in microvolts as an [`i32`]. + pub fn as_microvolts(self) -> i32 { + self.0 + } +} -- cgit v1.2.3