xref: /linux/rust/kernel/pwm.rs (revision 7b3dce814a15bc5d9fb6124cd945291012c4ebb9)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2025 Samsung Electronics Co., Ltd.
3 // Author: Michal Wilczynski <m.wilczynski@samsung.com>
4 
5 //! PWM subsystem abstractions.
6 //!
7 //! C header: [`include/linux/pwm.h`](srctree/include/linux/pwm.h).
8 
9 use crate::{
10     bindings,
11     prelude::*,
12     types::Opaque,
13 };
14 use core::convert::TryFrom;
15 
16 /// PWM polarity. Mirrors [`enum pwm_polarity`](srctree/include/linux/pwm.h).
17 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
18 pub enum Polarity {
19     /// Normal polarity (duty cycle defines the high period of the signal).
20     Normal,
21 
22     /// Inversed polarity (duty cycle defines the low period of the signal).
23     Inversed,
24 }
25 
26 impl TryFrom<bindings::pwm_polarity> for Polarity {
27     type Error = Error;
28 
29     fn try_from(polarity: bindings::pwm_polarity) -> Result<Self, Error> {
30         match polarity {
31             bindings::pwm_polarity_PWM_POLARITY_NORMAL => Ok(Polarity::Normal),
32             bindings::pwm_polarity_PWM_POLARITY_INVERSED => Ok(Polarity::Inversed),
33             _ => Err(EINVAL),
34         }
35     }
36 }
37 
38 impl From<Polarity> for bindings::pwm_polarity {
39     fn from(polarity: Polarity) -> Self {
40         match polarity {
41             Polarity::Normal => bindings::pwm_polarity_PWM_POLARITY_NORMAL,
42             Polarity::Inversed => bindings::pwm_polarity_PWM_POLARITY_INVERSED,
43         }
44     }
45 }
46 
47 /// Represents a PWM waveform configuration.
48 /// Mirrors struct [`struct pwm_waveform`](srctree/include/linux/pwm.h).
49 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
50 pub struct Waveform {
51     /// Total duration of one complete PWM cycle, in nanoseconds.
52     pub period_length_ns: u64,
53 
54     /// Duty-cycle active time, in nanoseconds.
55     ///
56     /// For a typical normal polarity configuration (active-high) this is the
57     /// high time of the signal.
58     pub duty_length_ns: u64,
59 
60     /// Duty-cycle start offset, in nanoseconds.
61     ///
62     /// Delay from the beginning of the period to the first active edge.
63     /// In most simple PWM setups this is `0`, so the duty cycle starts
64     /// immediately at each period’s start.
65     pub duty_offset_ns: u64,
66 }
67 
68 impl From<bindings::pwm_waveform> for Waveform {
69     fn from(wf: bindings::pwm_waveform) -> Self {
70         Waveform {
71             period_length_ns: wf.period_length_ns,
72             duty_length_ns: wf.duty_length_ns,
73             duty_offset_ns: wf.duty_offset_ns,
74         }
75     }
76 }
77 
78 impl From<Waveform> for bindings::pwm_waveform {
79     fn from(wf: Waveform) -> Self {
80         bindings::pwm_waveform {
81             period_length_ns: wf.period_length_ns,
82             duty_length_ns: wf.duty_length_ns,
83             duty_offset_ns: wf.duty_offset_ns,
84         }
85     }
86 }
87 
88 /// Wrapper for PWM state [`struct pwm_state`](srctree/include/linux/pwm.h).
89 #[repr(transparent)]
90 pub struct State(bindings::pwm_state);
91 
92 impl State {
93     /// Creates a `State` wrapper by taking ownership of a C `pwm_state` value.
94     pub(crate) fn from_c(c_state: bindings::pwm_state) -> Self {
95         State(c_state)
96     }
97 
98     /// Returns `true` if the PWM signal is enabled.
99     pub fn enabled(&self) -> bool {
100         self.0.enabled
101     }
102 }
103