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