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