@@ -16,7 +16,11 @@ use crate::{
1616 sync:: aref:: { ARef , AlwaysRefCounted } ,
1717 types:: Opaque , //
1818} ;
19- use core:: { marker:: PhantomData , ptr:: NonNull } ;
19+ use core:: {
20+ marker:: PhantomData ,
21+ ops:: Deref ,
22+ ptr:: NonNull , //
23+ } ;
2024
2125/// Represents a PWM waveform configuration.
2226/// Mirrors struct [`struct pwm_waveform`](srctree/include/linux/pwm.h).
@@ -174,7 +178,7 @@ pub struct RoundedWaveform<WfHw> {
174178}
175179
176180/// Trait defining the operations for a PWM driver.
177- pub trait PwmOps : ' static + Sized {
181+ pub trait PwmOps : ' static + Send + Sync + Sized {
178182 /// The driver-specific hardware representation of a waveform.
179183 ///
180184 /// This type must be [`Copy`], [`Default`], and fit within `PWM_WFHWSIZE`.
@@ -585,11 +589,12 @@ impl<T: PwmOps> Chip<T> {
585589 ///
586590 /// Returns an [`ARef<Chip>`] managing the chip's lifetime via refcounting
587591 /// on its embedded `struct device`.
588- pub fn new (
589- parent_dev : & device:: Device ,
592+ #[ allow( clippy:: new_ret_no_self) ]
593+ pub fn new < ' a > (
594+ parent_dev : & ' a device:: Device < Bound > ,
590595 num_channels : u32 ,
591596 data : impl pin_init:: PinInit < T , Error > ,
592- ) -> Result < ARef < Self > > {
597+ ) -> Result < UnregisteredChip < ' a , T > > {
593598 let sizeof_priv = core:: mem:: size_of :: < T > ( ) ;
594599 // SAFETY: `pwmchip_alloc` allocates memory for the C struct and our private data.
595600 let c_chip_ptr_raw =
@@ -624,7 +629,9 @@ impl<T: PwmOps> Chip<T> {
624629 // SAFETY: `chip_ptr_as_self` points to a valid `Chip` (layout-compatible with
625630 // `bindings::pwm_chip`) whose embedded device has refcount 1.
626631 // `ARef::from_raw` takes this pointer and manages it via `AlwaysRefCounted`.
627- Ok ( unsafe { ARef :: from_raw ( NonNull :: new_unchecked ( chip_ptr_as_self) ) } )
632+ let chip = unsafe { ARef :: from_raw ( NonNull :: new_unchecked ( chip_ptr_as_self) ) } ;
633+
634+ Ok ( UnregisteredChip { chip, parent_dev } )
628635 }
629636}
630637
@@ -655,50 +662,63 @@ unsafe impl<T: PwmOps> AlwaysRefCounted for Chip<T> {
655662// structure's state is managed and synchronized by the kernel's device model
656663// and PWM core locking mechanisms. Therefore, it is safe to move the `Chip`
657664// wrapper (and the pointer it contains) across threads.
658- unsafe impl < T : PwmOps + Send > Send for Chip < T > { }
665+ unsafe impl < T : PwmOps > Send for Chip < T > { }
659666
660667// SAFETY: It is safe for multiple threads to have shared access (`&Chip`) because
661668// the `Chip` data is immutable from the Rust side without holding the appropriate
662669// kernel locks, which the C core is responsible for. Any interior mutability is
663670// handled and synchronized by the C kernel code.
664- unsafe impl < T : PwmOps + Sync > Sync for Chip < T > { }
671+ unsafe impl < T : PwmOps > Sync for Chip < T > { }
665672
666- /// A resource guard that ensures `pwmchip_remove` is called on drop.
667- ///
668- /// This struct is intended to be managed by the `devres` framework by transferring its ownership
669- /// via [`devres::register`]. This ties the lifetime of the PWM chip registration
670- /// to the lifetime of the underlying device.
671- pub struct Registration < T : PwmOps > {
673+ /// A wrapper around `ARef<Chip<T>>` that ensures that `register` can only be called once.
674+ pub struct UnregisteredChip < ' a , T : PwmOps > {
672675 chip : ARef < Chip < T > > ,
676+ parent_dev : & ' a device:: Device < Bound > ,
673677}
674678
675- impl < T : ' static + PwmOps + Send + Sync > Registration < T > {
679+ impl < T : PwmOps > UnregisteredChip < ' _ , T > {
676680 /// Registers a PWM chip with the PWM subsystem.
677681 ///
678682 /// Transfers its ownership to the `devres` framework, which ties its lifetime
679683 /// to the parent device.
680684 /// On unbind of the parent device, the `devres` entry will be dropped, automatically
681685 /// calling `pwmchip_remove`. This function should be called from the driver's `probe`.
682- pub fn register ( dev : & device:: Device < Bound > , chip : ARef < Chip < T > > ) -> Result {
683- let chip_parent = chip. device ( ) . parent ( ) . ok_or ( EINVAL ) ?;
684- if dev. as_raw ( ) != chip_parent. as_raw ( ) {
685- return Err ( EINVAL ) ;
686- }
687-
688- let c_chip_ptr = chip. as_raw ( ) ;
686+ pub fn register ( self ) -> Result < ARef < Chip < T > > > {
687+ let c_chip_ptr = self . chip . as_raw ( ) ;
689688
690689 // SAFETY: `c_chip_ptr` points to a valid chip with its ops initialized.
691690 // `__pwmchip_add` is the C function to register the chip with the PWM core.
692691 unsafe {
693692 to_result ( bindings:: __pwmchip_add ( c_chip_ptr, core:: ptr:: null_mut ( ) ) ) ?;
694693 }
695694
696- let registration = Registration { chip } ;
695+ let registration = Registration {
696+ chip : ARef :: clone ( & self . chip ) ,
697+ } ;
698+
699+ devres:: register ( self . parent_dev , registration, GFP_KERNEL ) ?;
697700
698- devres :: register ( dev , registration , GFP_KERNEL )
701+ Ok ( self . chip )
699702 }
700703}
701704
705+ impl < 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.
718+ struct Registration < T : PwmOps > {
719+ chip : ARef < Chip < T > > ,
720+ }
721+
702722impl < T : PwmOps > Drop for Registration < T > {
703723 fn drop ( & mut self ) {
704724 let chip_raw = self . chip . as_raw ( ) ;
0 commit comments