mirror of https://github.com/torvalds/linux.git
rust: pwm: Add Kconfig and basic data structures
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`. - `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> Reviewed-by: Elle Rhumsaa <elle@weathered-steel.dev> Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com> Link: https://patch.msgid.link/20251016-rust-next-pwm-working-fan-for-sending-v16-2-a5df2405d2bd@samsung.com Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
This commit is contained in:
parent
ce284f8820
commit
7b3dce814a
|
|
@ -20763,6 +20763,14 @@ F: include/linux/pwm.h
|
||||||
F: include/linux/pwm_backlight.h
|
F: include/linux/pwm_backlight.h
|
||||||
K: pwm_(config|apply_might_sleep|apply_atomic|ops)
|
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
|
PXA GPIO DRIVER
|
||||||
M: Robert Jarzmik <robert.jarzmik@free.fr>
|
M: Robert Jarzmik <robert.jarzmik@free.fr>
|
||||||
L: linux-gpio@vger.kernel.org
|
L: linux-gpio@vger.kernel.org
|
||||||
|
|
|
||||||
|
|
@ -819,4 +819,16 @@ config PWM_XILINX
|
||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called pwm-xilinx.
|
will be called pwm-xilinx.
|
||||||
|
|
||||||
|
config RUST_PWM_ABSTRACTIONS
|
||||||
|
bool
|
||||||
|
depends on RUST
|
||||||
|
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
|
endif
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
|
#include <linux/pwm.h>
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
#include "poll.c"
|
#include "poll.c"
|
||||||
#include "processor.c"
|
#include "processor.c"
|
||||||
#include "property.c"
|
#include "property.c"
|
||||||
|
#include "pwm.c"
|
||||||
#include "rbtree.c"
|
#include "rbtree.c"
|
||||||
#include "rcu.c"
|
#include "rcu.c"
|
||||||
#include "refcount.c"
|
#include "refcount.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);
|
||||||
|
}
|
||||||
|
|
@ -129,6 +129,8 @@
|
||||||
pub mod seq_file;
|
pub mod seq_file;
|
||||||
pub mod sizes;
|
pub mod sizes;
|
||||||
mod static_assert;
|
mod static_assert;
|
||||||
|
#[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)]
|
||||||
|
pub mod pwm;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod std_vendor;
|
pub mod std_vendor;
|
||||||
pub mod str;
|
pub mod str;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
// 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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue