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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -819,4 +819,16 @@ 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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
#include <linux/pm_opp.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "poll.c"
|
||||
#include "processor.c"
|
||||
#include "property.c"
|
||||
#include "pwm.c"
|
||||
#include "rbtree.c"
|
||||
#include "rcu.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 sizes;
|
||||
mod static_assert;
|
||||
#[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)]
|
||||
pub mod pwm;
|
||||
#[doc(hidden)]
|
||||
pub mod std_vendor;
|
||||
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