[PATCH v13 2/7] rust: pwm: Add Kconfig and basic data structures
From: Michal Wilczynski <m.wilczynski@samsung.com>
Date: 2025-08-06 07:42:57
Also in:
linux-pwm, linux-riscv, lkml, rust-for-linux
Subsystem:
pwm subsystem, pwm subsystem bindings [rust], rust, the rest · Maintainers:
Uwe Kleine-König, Michal Wilczynski, Miguel Ojeda, Linus Torvalds
Introduce the foundational support for PWM abstractions in Rust. This commit adds the `RUST_PWM_ABSTRACTIONS` Kconfig option to enable the feature, along with the necessary build-system support and C helpers. It also introduces the first set of safe wrappers for the PWM subsystem, covering the basic data carrying C structs and enums: - `Polarity`: A safe wrapper for `enum pwm_polarity`. - `Waveform`: A wrapper for `struct pwm_waveform`. - `Args`: A wrapper for `struct pwm_args`. - `State`: A wrapper for `struct pwm_state`. These types provide memory safe, idiomatic Rust representations of the core PWM data structures and form the building blocks for the abstractions that will follow. Tested-by: Drew Fustini <fustini@kernel.org> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com> Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com> --- MAINTAINERS | 8 +++ drivers/pwm/Kconfig | 13 +++++ rust/bindings/bindings_helper.h | 1 + rust/helpers/helpers.c | 1 + rust/helpers/pwm.c | 20 +++++++ rust/kernel/lib.rs | 2 + rust/kernel/pwm.rs | 123 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 168 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index d780a6fcd163b49232bd51c4ecb845530048f61e..af85c50afbf785acc6f8dffdfaf3163e555b8b7e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS@@ -20371,6 +20371,14 @@ F: include/linux/pwm.h F: include/linux/pwm_backlight.h K: pwm_(config|apply_might_sleep|apply_atomic|ops) +PWM SUBSYSTEM BINDINGS [RUST] +M: Michal Wilczynski <m.wilczynski@samsung.com> +L: linux-pwm@vger.kernel.org +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/helpers/pwm.c +F: rust/kernel/pwm.rs + PXA GPIO DRIVER M: Robert Jarzmik <robert.jarzmik@free.fr> L: linux-gpio@vger.kernel.org
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index f00ce973dddf651287168b44228574f4d5c28dc0..2b608f4378138775ee3ba4d53f682952e1914118 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig@@ -800,4 +800,17 @@ config PWM_XILINX To compile this driver as a module, choose M here: the module will be called pwm-xilinx. + config RUST_PWM_ABSTRACTIONS + bool "Rust PWM abstractions support" + depends on RUST + depends on PWM=y + help + This option enables the safe Rust abstraction layer for the PWM + subsystem. It provides idiomatic wrappers and traits necessary for + writing PWM controller drivers in Rust. + + The abstractions handle resource management (like memory and reference + counting) and provide safe interfaces to the underlying C core, + allowing driver logic to be written in safe Rust. + endif
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 84d60635e8a9baef1f1a1b2752dc0fa044f8542f..7a06ee5781eadc9f21ccd456b574a9cb152cd58c 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h@@ -66,6 +66,7 @@ #include <linux/pm_opp.h> #include <linux/poll.h> #include <linux/property.h> +#include <linux/pwm.h> #include <linux/refcount.h> #include <linux/regulator/consumer.h> #include <linux/sched.h>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 2bb13285825b7769f818ab675fa9b979b458c076..0d1df4298dffe1e493af7ea6861e6c55b799a059 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c@@ -35,6 +35,7 @@ #include "pid_namespace.c" #include "poll.c" #include "property.c" +#include "pwm.c" #include "rbtree.c" #include "regulator.c" #include "rcu.c"
diff --git a/rust/helpers/pwm.c b/rust/helpers/pwm.c
new file mode 100644
index 0000000000000000000000000000000000000000..d75c588863685d3990b525bb1b84aa4bc35ac397
--- /dev/null
+++ b/rust/helpers/pwm.c@@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2025 Samsung Electronics Co., Ltd. +// Author: Michal Wilczynski <m.wilczynski@samsung.com> + +#include <linux/pwm.h> + +struct device *rust_helper_pwmchip_parent(const struct pwm_chip *chip) +{ + return pwmchip_parent(chip); +} + +void *rust_helper_pwmchip_get_drvdata(struct pwm_chip *chip) +{ + return pwmchip_get_drvdata(chip); +} + +void rust_helper_pwmchip_set_drvdata(struct pwm_chip *chip, void *data) +{ + pwmchip_set_drvdata(chip, data); +}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index c2d1b93752050743e232f040ec1d3137b5e39aa4..9c3605cff348b274e9ab6f4857a7e010e9ef5ccc 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs@@ -114,6 +114,8 @@ pub mod seq_file; pub mod sizes; mod static_assert; +#[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)] +pub mod pwm; #[doc(hidden)] pub mod std_vendor; pub mod str;
diff --git a/rust/kernel/pwm.rs b/rust/kernel/pwm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..57675a3dfca12033355670deb210ca66f8469334
--- /dev/null
+++ b/rust/kernel/pwm.rs@@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2025 Samsung Electronics Co., Ltd. +// Author: Michal Wilczynski <m.wilczynski@samsung.com> + +//! PWM subsystem abstractions. +//! +//! C header: [`include/linux/pwm.h`](srctree/include/linux/pwm.h). + +use crate::{ + bindings, + prelude::*, + types::Opaque, +}; +use core::convert::TryFrom; + +/// PWM polarity. Mirrors [`enum pwm_polarity`](srctree/include/linux/pwm.h). +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Polarity { + /// Normal polarity (duty cycle defines the high period of the signal). + Normal, + + /// Inversed polarity (duty cycle defines the low period of the signal). + Inversed, +} + +impl TryFrom<bindings::pwm_polarity> for Polarity { + type Error = Error; + + fn try_from(polarity: bindings::pwm_polarity) -> Result<Self, Error> { + match polarity { + bindings::pwm_polarity_PWM_POLARITY_NORMAL => Ok(Polarity::Normal), + bindings::pwm_polarity_PWM_POLARITY_INVERSED => Ok(Polarity::Inversed), + _ => Err(EINVAL), + } + } +} + +impl From<Polarity> for bindings::pwm_polarity { + fn from(polarity: Polarity) -> Self { + match polarity { + Polarity::Normal => bindings::pwm_polarity_PWM_POLARITY_NORMAL, + Polarity::Inversed => bindings::pwm_polarity_PWM_POLARITY_INVERSED, + } + } +} + +/// Represents a PWM waveform configuration. +/// Mirrors struct [`struct pwm_waveform`](srctree/include/linux/pwm.h). +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct Waveform { + /// Total duration of one complete PWM cycle, in nanoseconds. + pub period_length_ns: u64, + + /// Duty-cycle active time, in nanoseconds. + /// + /// For a typical normal polarity configuration (active-high) this is the + /// high time of the signal. + pub duty_length_ns: u64, + + /// Duty-cycle start offset, in nanoseconds. + /// + /// Delay from the beginning of the period to the first active edge. + /// In most simple PWM setups this is `0`, so the duty cycle starts + /// immediately at each period’s start. + pub duty_offset_ns: u64, +} + +impl From<bindings::pwm_waveform> for Waveform { + fn from(wf: bindings::pwm_waveform) -> Self { + Waveform { + period_length_ns: wf.period_length_ns, + duty_length_ns: wf.duty_length_ns, + duty_offset_ns: wf.duty_offset_ns, + } + } +} + +impl From<Waveform> for bindings::pwm_waveform { + fn from(wf: Waveform) -> Self { + bindings::pwm_waveform { + period_length_ns: wf.period_length_ns, + duty_length_ns: wf.duty_length_ns, + duty_offset_ns: wf.duty_offset_ns, + } + } +} + +/// Wrapper for board-dependent PWM arguments [`struct pwm_args`](srctree/include/linux/pwm.h). +#[repr(transparent)] +pub struct Args(bindings::pwm_args); + +impl Args { + /// Creates a `Args` wrapper by taking ownership of a C `pwm_args` value. + pub(crate) fn from_c(c_args: bindings::pwm_args) -> Self { + Args(c_args) + } + + /// Returns the period of the PWM signal in nanoseconds. + pub fn period(&self) -> u64 { + self.0.period + } + + /// Returns the polarity of the PWM signal. + pub fn polarity(&self) -> Result<Polarity, Error> { + Polarity::try_from(self.0.polarity) + } +} + +/// Wrapper for PWM state [`struct pwm_state`](srctree/include/linux/pwm.h). +#[repr(transparent)] +pub struct State(bindings::pwm_state); + +impl State { + /// Creates a `State` wrapper by taking ownership of a C `pwm_state` value. + pub(crate) fn from_c(c_state: bindings::pwm_state) -> Self { + State(c_state) + } + + /// Returns `true` if the PWM signal is enabled. + pub fn enabled(&self) -> bool { + self.0.enabled + } +}
--
2.34.1