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