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