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