kernel/
pwm.rs

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
9use crate::{
10    bindings,
11    container_of,
12    device::{self, Bound},
13    devres,
14    error::{self, to_result},
15    prelude::*,
16    sync::aref::{ARef, AlwaysRefCounted},
17    types::Opaque, //
18};
19use core::{
20    marker::PhantomData,
21    ops::Deref,
22    ptr::NonNull, //
23};
24
25/// Represents a PWM waveform configuration.
26/// Mirrors struct [`struct pwm_waveform`](srctree/include/linux/pwm.h).
27#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
28pub struct Waveform {
29    /// Total duration of one complete PWM cycle, in nanoseconds.
30    pub period_length_ns: u64,
31
32    /// Duty-cycle active time, in nanoseconds.
33    ///
34    /// For a typical normal polarity configuration (active-high) this is the
35    /// high time of the signal.
36    pub duty_length_ns: u64,
37
38    /// Duty-cycle start offset, in nanoseconds.
39    ///
40    /// Delay from the beginning of the period to the first active edge.
41    /// In most simple PWM setups this is `0`, so the duty cycle starts
42    /// immediately at each period’s start.
43    pub duty_offset_ns: u64,
44}
45
46impl From<bindings::pwm_waveform> for Waveform {
47    fn from(wf: bindings::pwm_waveform) -> Self {
48        Waveform {
49            period_length_ns: wf.period_length_ns,
50            duty_length_ns: wf.duty_length_ns,
51            duty_offset_ns: wf.duty_offset_ns,
52        }
53    }
54}
55
56impl From<Waveform> for bindings::pwm_waveform {
57    fn from(wf: Waveform) -> Self {
58        bindings::pwm_waveform {
59            period_length_ns: wf.period_length_ns,
60            duty_length_ns: wf.duty_length_ns,
61            duty_offset_ns: wf.duty_offset_ns,
62        }
63    }
64}
65
66/// Describes the outcome of a `round_waveform` operation.
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum RoundingOutcome {
69    /// The requested waveform was achievable exactly or by rounding values down.
70    ExactOrRoundedDown,
71
72    /// The requested waveform could only be achieved by rounding up.
73    RoundedUp,
74}
75
76/// Wrapper for a PWM device [`struct pwm_device`](srctree/include/linux/pwm.h).
77#[repr(transparent)]
78pub struct Device(Opaque<bindings::pwm_device>);
79
80impl Device {
81    /// Creates a reference to a [`Device`] from a valid C pointer.
82    ///
83    /// # Safety
84    ///
85    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
86    /// returned [`Device`] reference.
87    pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::pwm_device) -> &'a Self {
88        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
89        // `Device` type being transparent makes the cast ok.
90        unsafe { &*ptr.cast::<Self>() }
91    }
92
93    /// Returns a raw pointer to the underlying `pwm_device`.
94    fn as_raw(&self) -> *mut bindings::pwm_device {
95        self.0.get()
96    }
97
98    /// Gets the hardware PWM index for this device within its chip.
99    pub fn hwpwm(&self) -> u32 {
100        // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime.
101        unsafe { (*self.as_raw()).hwpwm }
102    }
103
104    /// Gets a reference to the parent `Chip` that this device belongs to.
105    pub fn chip<T: PwmOps>(&self) -> &Chip<T> {
106        // SAFETY: `self.as_raw()` provides a valid pointer. (*self.as_raw()).chip
107        // is assumed to be a valid pointer to `pwm_chip` managed by the kernel.
108        // Chip::from_raw's safety conditions must be met.
109        unsafe { Chip::<T>::from_raw((*self.as_raw()).chip) }
110    }
111
112    /// Gets the label for this PWM device, if any.
113    pub fn label(&self) -> Option<&CStr> {
114        // SAFETY: self.as_raw() provides a valid pointer.
115        let label_ptr = unsafe { (*self.as_raw()).label };
116        if label_ptr.is_null() {
117            return None;
118        }
119
120        // SAFETY: label_ptr is non-null and points to a C string
121        // managed by the kernel, valid for the lifetime of the PWM device.
122        Some(unsafe { CStr::from_char_ptr(label_ptr) })
123    }
124
125    /// Sets the PWM waveform configuration and enables the PWM signal.
126    pub fn set_waveform(&self, wf: &Waveform, exact: bool) -> Result {
127        let c_wf = bindings::pwm_waveform::from(*wf);
128
129        // SAFETY: `self.as_raw()` provides a valid `*mut pwm_device` pointer.
130        // `&c_wf` is a valid pointer to a `pwm_waveform` struct. The C function
131        // handles all necessary internal locking.
132        let ret = unsafe { bindings::pwm_set_waveform_might_sleep(self.as_raw(), &c_wf, exact) };
133        to_result(ret)
134    }
135
136    /// Queries the hardware for the configuration it would apply for a given
137    /// request.
138    pub fn round_waveform(&self, wf: &mut Waveform) -> Result<RoundingOutcome> {
139        let mut c_wf = bindings::pwm_waveform::from(*wf);
140
141        // SAFETY: `self.as_raw()` provides a valid `*mut pwm_device` pointer.
142        // `&mut c_wf` is a valid pointer to a mutable `pwm_waveform` struct that
143        // the C function will update.
144        let ret = unsafe { bindings::pwm_round_waveform_might_sleep(self.as_raw(), &mut c_wf) };
145
146        to_result(ret)?;
147
148        *wf = Waveform::from(c_wf);
149
150        if ret == 1 {
151            Ok(RoundingOutcome::RoundedUp)
152        } else {
153            Ok(RoundingOutcome::ExactOrRoundedDown)
154        }
155    }
156
157    /// Reads the current waveform configuration directly from the hardware.
158    pub fn get_waveform(&self) -> Result<Waveform> {
159        let mut c_wf = bindings::pwm_waveform::default();
160
161        // SAFETY: `self.as_raw()` is a valid pointer. We provide a valid pointer
162        // to a stack-allocated `pwm_waveform` struct for the kernel to fill.
163        let ret = unsafe { bindings::pwm_get_waveform_might_sleep(self.as_raw(), &mut c_wf) };
164
165        to_result(ret)?;
166
167        Ok(Waveform::from(c_wf))
168    }
169}
170
171/// The result of a `round_waveform_tohw` operation.
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub struct RoundedWaveform<WfHw> {
174    /// A status code, 0 for success or 1 if values were rounded up.
175    pub status: c_int,
176    /// The driver-specific hardware representation of the waveform.
177    pub hardware_waveform: WfHw,
178}
179
180/// Trait defining the operations for a PWM driver.
181pub trait PwmOps: 'static + Send + Sync + Sized {
182    /// The driver-specific hardware representation of a waveform.
183    ///
184    /// This type must be [`Copy`], [`Default`], and fit within `PWM_WFHWSIZE`.
185    type WfHw: Copy + Default;
186
187    /// Optional hook for when a PWM device is requested.
188    fn request(_chip: &Chip<Self>, _pwm: &Device, _parent_dev: &device::Device<Bound>) -> Result {
189        Ok(())
190    }
191
192    /// Optional hook for capturing a PWM signal.
193    fn capture(
194        _chip: &Chip<Self>,
195        _pwm: &Device,
196        _result: &mut bindings::pwm_capture,
197        _timeout: usize,
198        _parent_dev: &device::Device<Bound>,
199    ) -> Result {
200        Err(ENOTSUPP)
201    }
202
203    /// Convert a generic waveform to the hardware-specific representation.
204    /// This is typically a pure calculation and does not perform I/O.
205    fn round_waveform_tohw(
206        _chip: &Chip<Self>,
207        _pwm: &Device,
208        _wf: &Waveform,
209    ) -> Result<RoundedWaveform<Self::WfHw>> {
210        Err(ENOTSUPP)
211    }
212
213    /// Convert a hardware-specific representation back to a generic waveform.
214    /// This is typically a pure calculation and does not perform I/O.
215    fn round_waveform_fromhw(
216        _chip: &Chip<Self>,
217        _pwm: &Device,
218        _wfhw: &Self::WfHw,
219        _wf: &mut Waveform,
220    ) -> Result {
221        Err(ENOTSUPP)
222    }
223
224    /// Read the current hardware configuration into the hardware-specific representation.
225    fn read_waveform(
226        _chip: &Chip<Self>,
227        _pwm: &Device,
228        _parent_dev: &device::Device<Bound>,
229    ) -> Result<Self::WfHw> {
230        Err(ENOTSUPP)
231    }
232
233    /// Write a hardware-specific waveform configuration to the hardware.
234    fn write_waveform(
235        _chip: &Chip<Self>,
236        _pwm: &Device,
237        _wfhw: &Self::WfHw,
238        _parent_dev: &device::Device<Bound>,
239    ) -> Result {
240        Err(ENOTSUPP)
241    }
242}
243
244/// Bridges Rust `PwmOps` to the C `pwm_ops` vtable.
245struct Adapter<T: PwmOps> {
246    _p: PhantomData<T>,
247}
248
249impl<T: PwmOps> Adapter<T> {
250    const VTABLE: PwmOpsVTable = create_pwm_ops::<T>();
251
252    /// # Safety
253    ///
254    /// `wfhw_ptr` must be valid for writes of `size_of::<T::WfHw>()` bytes.
255    unsafe fn serialize_wfhw(wfhw: &T::WfHw, wfhw_ptr: *mut c_void) -> Result {
256        let size = core::mem::size_of::<T::WfHw>();
257
258        build_assert!(size <= bindings::PWM_WFHWSIZE as usize);
259
260        // SAFETY: The caller ensures `wfhw_ptr` is valid for `size` bytes.
261        unsafe {
262            core::ptr::copy_nonoverlapping(
263                core::ptr::from_ref::<T::WfHw>(wfhw).cast::<u8>(),
264                wfhw_ptr.cast::<u8>(),
265                size,
266            );
267        }
268
269        Ok(())
270    }
271
272    /// # Safety
273    ///
274    /// `wfhw_ptr` must be valid for reads of `size_of::<T::WfHw>()` bytes.
275    unsafe fn deserialize_wfhw(wfhw_ptr: *const c_void) -> Result<T::WfHw> {
276        let size = core::mem::size_of::<T::WfHw>();
277
278        build_assert!(size <= bindings::PWM_WFHWSIZE as usize);
279
280        let mut wfhw = T::WfHw::default();
281        // SAFETY: The caller ensures `wfhw_ptr` is valid for `size` bytes.
282        unsafe {
283            core::ptr::copy_nonoverlapping(
284                wfhw_ptr.cast::<u8>(),
285                core::ptr::from_mut::<T::WfHw>(&mut wfhw).cast::<u8>(),
286                size,
287            );
288        }
289
290        Ok(wfhw)
291    }
292
293    /// # Safety
294    ///
295    /// `dev` must be a valid pointer to a `bindings::device` embedded within a
296    /// `bindings::pwm_chip`. This function is called by the device core when the
297    /// last reference to the device is dropped.
298    unsafe extern "C" fn release_callback(dev: *mut bindings::device) {
299        // SAFETY: The function's contract guarantees that `dev` points to a `device`
300        // field embedded within a valid `pwm_chip`. `container_of!` can therefore
301        // safely calculate the address of the containing struct.
302        let c_chip_ptr = unsafe { container_of!(dev, bindings::pwm_chip, dev) };
303
304        // SAFETY: `c_chip_ptr` is a valid pointer to a `pwm_chip` as established
305        // above. Calling this FFI function is safe.
306        let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) };
307
308        // SAFETY: The driver data was initialized in `new`. We run its destructor here.
309        unsafe { core::ptr::drop_in_place(drvdata_ptr.cast::<T>()) };
310
311        // Now, call the original release function to free the `pwm_chip` itself.
312        // SAFETY: `dev` is the valid pointer passed into this callback, which is
313        // the expected argument for `pwmchip_release`.
314        unsafe {
315            bindings::pwmchip_release(dev);
316        }
317    }
318
319    /// # Safety
320    ///
321    /// Pointers from C must be valid.
322    unsafe extern "C" fn request_callback(
323        chip_ptr: *mut bindings::pwm_chip,
324        pwm_ptr: *mut bindings::pwm_device,
325    ) -> c_int {
326        // SAFETY: PWM core guarentees `chip_ptr` and `pwm_ptr` are valid pointers.
327        let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) };
328
329        // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks.
330        let bound_parent = unsafe { chip.bound_parent_device() };
331        match T::request(chip, pwm, bound_parent) {
332            Ok(()) => 0,
333            Err(e) => e.to_errno(),
334        }
335    }
336
337    /// # Safety
338    ///
339    /// Pointers from C must be valid.
340    unsafe extern "C" fn capture_callback(
341        chip_ptr: *mut bindings::pwm_chip,
342        pwm_ptr: *mut bindings::pwm_device,
343        res: *mut bindings::pwm_capture,
344        timeout: usize,
345    ) -> c_int {
346        // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid
347        // pointers.
348        let (chip, pwm, result) = unsafe {
349            (
350                Chip::<T>::from_raw(chip_ptr),
351                Device::from_raw(pwm_ptr),
352                &mut *res,
353            )
354        };
355
356        // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks.
357        let bound_parent = unsafe { chip.bound_parent_device() };
358        match T::capture(chip, pwm, result, timeout, bound_parent) {
359            Ok(()) => 0,
360            Err(e) => e.to_errno(),
361        }
362    }
363
364    /// # Safety
365    ///
366    /// Pointers from C must be valid.
367    unsafe extern "C" fn round_waveform_tohw_callback(
368        chip_ptr: *mut bindings::pwm_chip,
369        pwm_ptr: *mut bindings::pwm_device,
370        wf_ptr: *const bindings::pwm_waveform,
371        wfhw_ptr: *mut c_void,
372    ) -> c_int {
373        // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid
374        // pointers.
375        let (chip, pwm, wf) = unsafe {
376            (
377                Chip::<T>::from_raw(chip_ptr),
378                Device::from_raw(pwm_ptr),
379                Waveform::from(*wf_ptr),
380            )
381        };
382        match T::round_waveform_tohw(chip, pwm, &wf) {
383            Ok(rounded) => {
384                // SAFETY: `wfhw_ptr` is valid per this function's safety contract.
385                if unsafe { Self::serialize_wfhw(&rounded.hardware_waveform, wfhw_ptr) }.is_err() {
386                    return EINVAL.to_errno();
387                }
388                rounded.status
389            }
390            Err(e) => e.to_errno(),
391        }
392    }
393
394    /// # Safety
395    ///
396    /// Pointers from C must be valid.
397    unsafe extern "C" fn round_waveform_fromhw_callback(
398        chip_ptr: *mut bindings::pwm_chip,
399        pwm_ptr: *mut bindings::pwm_device,
400        wfhw_ptr: *const c_void,
401        wf_ptr: *mut bindings::pwm_waveform,
402    ) -> c_int {
403        // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid
404        // pointers.
405        let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) };
406        // SAFETY: `deserialize_wfhw`'s safety contract is met by this function's contract.
407        let wfhw = match unsafe { Self::deserialize_wfhw(wfhw_ptr) } {
408            Ok(v) => v,
409            Err(e) => return e.to_errno(),
410        };
411
412        let mut rust_wf = Waveform::default();
413        match T::round_waveform_fromhw(chip, pwm, &wfhw, &mut rust_wf) {
414            Ok(()) => {
415                // SAFETY: `wf_ptr` is guaranteed valid by the C caller.
416                unsafe {
417                    *wf_ptr = rust_wf.into();
418                };
419                0
420            }
421            Err(e) => e.to_errno(),
422        }
423    }
424
425    /// # Safety
426    ///
427    /// Pointers from C must be valid.
428    unsafe extern "C" fn read_waveform_callback(
429        chip_ptr: *mut bindings::pwm_chip,
430        pwm_ptr: *mut bindings::pwm_device,
431        wfhw_ptr: *mut c_void,
432    ) -> c_int {
433        // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid
434        // pointers.
435        let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) };
436
437        // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks.
438        let bound_parent = unsafe { chip.bound_parent_device() };
439        match T::read_waveform(chip, pwm, bound_parent) {
440            // SAFETY: `wfhw_ptr` is valid per this function's safety contract.
441            Ok(wfhw) => match unsafe { Self::serialize_wfhw(&wfhw, wfhw_ptr) } {
442                Ok(()) => 0,
443                Err(e) => e.to_errno(),
444            },
445            Err(e) => e.to_errno(),
446        }
447    }
448
449    /// # Safety
450    ///
451    /// Pointers from C must be valid.
452    unsafe extern "C" fn write_waveform_callback(
453        chip_ptr: *mut bindings::pwm_chip,
454        pwm_ptr: *mut bindings::pwm_device,
455        wfhw_ptr: *const c_void,
456    ) -> c_int {
457        // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid
458        // pointers.
459        let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) };
460
461        // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks.
462        let bound_parent = unsafe { chip.bound_parent_device() };
463
464        // SAFETY: `wfhw_ptr` is valid per this function's safety contract.
465        let wfhw = match unsafe { Self::deserialize_wfhw(wfhw_ptr) } {
466            Ok(v) => v,
467            Err(e) => return e.to_errno(),
468        };
469        match T::write_waveform(chip, pwm, &wfhw, bound_parent) {
470            Ok(()) => 0,
471            Err(e) => e.to_errno(),
472        }
473    }
474}
475
476/// VTable structure wrapper for PWM operations.
477/// Mirrors [`struct pwm_ops`](srctree/include/linux/pwm.h).
478#[repr(transparent)]
479pub struct PwmOpsVTable(bindings::pwm_ops);
480
481// SAFETY: PwmOpsVTable is Send. The vtable contains only function pointers
482// and a size, which are simple data types that can be safely moved across
483// threads. The thread-safety of calling these functions is handled by the
484// kernel's locking mechanisms.
485unsafe impl Send for PwmOpsVTable {}
486
487// SAFETY: PwmOpsVTable is Sync. The vtable is immutable after it is created,
488// so it can be safely referenced and accessed concurrently by multiple threads
489// e.g. to read the function pointers.
490unsafe impl Sync for PwmOpsVTable {}
491
492impl PwmOpsVTable {
493    /// Returns a raw pointer to the underlying `pwm_ops` struct.
494    pub(crate) fn as_raw(&self) -> *const bindings::pwm_ops {
495        &self.0
496    }
497}
498
499/// Creates a PWM operations vtable for a type `T` that implements `PwmOps`.
500///
501/// This is used to bridge Rust trait implementations to the C `struct pwm_ops`
502/// expected by the kernel.
503pub const fn create_pwm_ops<T: PwmOps>() -> PwmOpsVTable {
504    // SAFETY: `core::mem::zeroed()` is unsafe. For `pwm_ops`, all fields are
505    // `Option<extern "C" fn(...)>` or data, so a zeroed pattern (None/0) is valid initially.
506    let mut ops: bindings::pwm_ops = unsafe { core::mem::zeroed() };
507
508    ops.request = Some(Adapter::<T>::request_callback);
509    ops.capture = Some(Adapter::<T>::capture_callback);
510
511    ops.round_waveform_tohw = Some(Adapter::<T>::round_waveform_tohw_callback);
512    ops.round_waveform_fromhw = Some(Adapter::<T>::round_waveform_fromhw_callback);
513    ops.read_waveform = Some(Adapter::<T>::read_waveform_callback);
514    ops.write_waveform = Some(Adapter::<T>::write_waveform_callback);
515    ops.sizeof_wfhw = core::mem::size_of::<T::WfHw>();
516
517    PwmOpsVTable(ops)
518}
519
520/// Wrapper for a PWM chip/controller ([`struct pwm_chip`](srctree/include/linux/pwm.h)).
521#[repr(transparent)]
522pub struct Chip<T: PwmOps>(Opaque<bindings::pwm_chip>, PhantomData<T>);
523
524impl<T: PwmOps> Chip<T> {
525    /// Creates a reference to a [`Chip`] from a valid pointer.
526    ///
527    /// # Safety
528    ///
529    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
530    /// returned [`Chip`] reference.
531    pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::pwm_chip) -> &'a Self {
532        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
533        // `Chip` type being transparent makes the cast ok.
534        unsafe { &*ptr.cast::<Self>() }
535    }
536
537    /// Returns a raw pointer to the underlying `pwm_chip`.
538    pub(crate) fn as_raw(&self) -> *mut bindings::pwm_chip {
539        self.0.get()
540    }
541
542    /// Gets the number of PWM channels (hardware PWMs) on this chip.
543    pub fn num_channels(&self) -> u32 {
544        // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime.
545        unsafe { (*self.as_raw()).npwm }
546    }
547
548    /// Returns `true` if the chip supports atomic operations for configuration.
549    pub fn is_atomic(&self) -> bool {
550        // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime.
551        unsafe { (*self.as_raw()).atomic }
552    }
553
554    /// Returns a reference to the embedded `struct device` abstraction.
555    pub fn device(&self) -> &device::Device {
556        // SAFETY:
557        // - `self.as_raw()` provides a valid pointer to `bindings::pwm_chip`.
558        // - The `dev` field is an instance of `bindings::device` embedded
559        //   within `pwm_chip`.
560        // - Taking a pointer to this embedded field is valid.
561        // - `device::Device` is `#[repr(transparent)]`.
562        // - The lifetime of the returned reference is tied to `self`.
563        unsafe { device::Device::from_raw(&raw mut (*self.as_raw()).dev) }
564    }
565
566    /// Gets the typed driver specific data associated with this chip's embedded device.
567    pub fn drvdata(&self) -> &T {
568        // SAFETY: `pwmchip_get_drvdata` returns the pointer to the private data area,
569        // which we know holds our `T`. The pointer is valid for the lifetime of `self`.
570        unsafe { &*bindings::pwmchip_get_drvdata(self.as_raw()).cast::<T>() }
571    }
572
573    /// Returns a reference to the parent device of this PWM chip's device.
574    ///
575    /// # Safety
576    ///
577    /// The caller must guarantee that the parent device exists and is bound.
578    /// This is guaranteed by the PWM core during `PwmOps` callbacks.
579    unsafe fn bound_parent_device(&self) -> &device::Device<Bound> {
580        // SAFETY: Per the function's safety contract, the parent device exists.
581        let parent = unsafe { self.device().parent().unwrap_unchecked() };
582
583        // SAFETY: Per the function's safety contract, the parent device is bound.
584        // This is guaranteed by the PWM core during `PwmOps` callbacks.
585        unsafe { parent.as_bound() }
586    }
587
588    /// Allocates and wraps a PWM chip using `bindings::pwmchip_alloc`.
589    ///
590    /// Returns an [`ARef<Chip>`] managing the chip's lifetime via refcounting
591    /// on its embedded `struct device`.
592    #[allow(clippy::new_ret_no_self)]
593    pub fn new<'a>(
594        parent_dev: &'a device::Device<Bound>,
595        num_channels: u32,
596        data: impl pin_init::PinInit<T, Error>,
597    ) -> Result<UnregisteredChip<'a, T>> {
598        let sizeof_priv = core::mem::size_of::<T>();
599        // SAFETY: `pwmchip_alloc` allocates memory for the C struct and our private data.
600        let c_chip_ptr_raw =
601            unsafe { bindings::pwmchip_alloc(parent_dev.as_raw(), num_channels, sizeof_priv) };
602
603        let c_chip_ptr: *mut bindings::pwm_chip = error::from_err_ptr(c_chip_ptr_raw)?;
604
605        // SAFETY: The `drvdata` pointer is the start of the private area, which is where
606        // we will construct our `T` object.
607        let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) };
608
609        // SAFETY: We construct the `T` object in-place in the allocated private memory.
610        unsafe { data.__pinned_init(drvdata_ptr.cast())? };
611
612        // SAFETY: `c_chip_ptr` points to a valid chip.
613        unsafe {
614            (*c_chip_ptr).dev.release = Some(Adapter::<T>::release_callback);
615        }
616
617        // SAFETY: `c_chip_ptr` points to a valid chip.
618        // The `Adapter`'s `VTABLE` has a 'static lifetime, so the pointer
619        // returned by `as_raw()` is always valid.
620        unsafe {
621            (*c_chip_ptr).ops = Adapter::<T>::VTABLE.as_raw();
622        }
623
624        // Cast the `*mut bindings::pwm_chip` to `*mut Chip`. This is valid because
625        // `Chip` is `repr(transparent)` over `Opaque<bindings::pwm_chip>`, and
626        // `Opaque<T>` is `repr(transparent)` over `T`.
627        let chip_ptr_as_self = c_chip_ptr.cast::<Self>();
628
629        // SAFETY: `chip_ptr_as_self` points to a valid `Chip` (layout-compatible with
630        // `bindings::pwm_chip`) whose embedded device has refcount 1.
631        // `ARef::from_raw` takes this pointer and manages it via `AlwaysRefCounted`.
632        let chip = unsafe { ARef::from_raw(NonNull::new_unchecked(chip_ptr_as_self)) };
633
634        Ok(UnregisteredChip { chip, parent_dev })
635    }
636}
637
638// SAFETY: Implements refcounting for `Chip` using the embedded `struct device`.
639unsafe impl<T: PwmOps> AlwaysRefCounted for Chip<T> {
640    #[inline]
641    fn inc_ref(&self) {
642        // SAFETY: `self.0.get()` points to a valid `pwm_chip` because `self` exists.
643        // The embedded `dev` is valid. `get_device` increments its refcount.
644        unsafe {
645            bindings::get_device(&raw mut (*self.0.get()).dev);
646        }
647    }
648
649    #[inline]
650    unsafe fn dec_ref(obj: NonNull<Chip<T>>) {
651        let c_chip_ptr = obj.cast::<bindings::pwm_chip>().as_ptr();
652
653        // SAFETY: `obj` is a valid pointer to a `Chip` (and thus `bindings::pwm_chip`)
654        // with a non-zero refcount. `put_device` handles decrement and final release.
655        unsafe {
656            bindings::put_device(&raw mut (*c_chip_ptr).dev);
657        }
658    }
659}
660
661// SAFETY: `Chip` is a wrapper around `*mut bindings::pwm_chip`. The underlying C
662// structure's state is managed and synchronized by the kernel's device model
663// and PWM core locking mechanisms. Therefore, it is safe to move the `Chip`
664// wrapper (and the pointer it contains) across threads.
665unsafe impl<T: PwmOps> Send for Chip<T> {}
666
667// SAFETY: It is safe for multiple threads to have shared access (`&Chip`) because
668// the `Chip` data is immutable from the Rust side without holding the appropriate
669// kernel locks, which the C core is responsible for. Any interior mutability is
670// handled and synchronized by the C kernel code.
671unsafe impl<T: PwmOps> Sync for Chip<T> {}
672
673/// A wrapper around `ARef<Chip<T>>` that ensures that `register` can only be called once.
674pub struct UnregisteredChip<'a, T: PwmOps> {
675    chip: ARef<Chip<T>>,
676    parent_dev: &'a device::Device<Bound>,
677}
678
679impl<T: PwmOps> UnregisteredChip<'_, T> {
680    /// Registers a PWM chip with the PWM subsystem.
681    ///
682    /// Transfers its ownership to the `devres` framework, which ties its lifetime
683    /// to the parent device.
684    /// On unbind of the parent device, the `devres` entry will be dropped, automatically
685    /// calling `pwmchip_remove`. This function should be called from the driver's `probe`.
686    pub fn register(self) -> Result<ARef<Chip<T>>> {
687        let c_chip_ptr = self.chip.as_raw();
688
689        // SAFETY: `c_chip_ptr` points to a valid chip with its ops initialized.
690        // `__pwmchip_add` is the C function to register the chip with the PWM core.
691        unsafe {
692            to_result(bindings::__pwmchip_add(c_chip_ptr, core::ptr::null_mut()))?;
693        }
694
695        let registration = Registration {
696            chip: ARef::clone(&self.chip),
697        };
698
699        devres::register(self.parent_dev, registration, GFP_KERNEL)?;
700
701        Ok(self.chip)
702    }
703}
704
705impl<T: PwmOps> Deref for UnregisteredChip<'_, T> {
706    type Target = Chip<T>;
707
708    fn deref(&self) -> &Self::Target {
709        &self.chip
710    }
711}
712
713/// A resource guard that ensures `pwmchip_remove` is called on drop.
714///
715/// This struct is intended to be managed by the `devres` framework by transferring its ownership
716/// via [`devres::register`]. This ties the lifetime of the PWM chip registration
717/// to the lifetime of the underlying device.
718struct Registration<T: PwmOps> {
719    chip: ARef<Chip<T>>,
720}
721
722impl<T: PwmOps> Drop for Registration<T> {
723    fn drop(&mut self) {
724        let chip_raw = self.chip.as_raw();
725
726        // SAFETY: `chip_raw` points to a chip that was successfully registered.
727        // `bindings::pwmchip_remove` is the correct C function to unregister it.
728        // This `drop` implementation is called automatically by `devres` on driver unbind.
729        unsafe {
730            bindings::pwmchip_remove(chip_raw);
731        }
732    }
733}
734
735/// Declares a kernel module that exposes a single PWM driver.
736///
737/// # Examples
738///
739///```ignore
740/// kernel::module_pwm_platform_driver! {
741///     type: MyDriver,
742///     name: "Module name",
743///     authors: ["Author name"],
744///     description: "Description",
745///     license: "GPL v2",
746/// }
747///```
748#[macro_export]
749macro_rules! module_pwm_platform_driver {
750    ($($user_args:tt)*) => {
751        $crate::module_platform_driver! {
752            $($user_args)*
753            imports_ns: ["PWM"],
754        }
755    };
756}