drivers/pwm/pwm_th1520.rs

Source file repositories/reference/linux-study-clean/drivers/pwm/pwm_th1520.rs

File Facts

System
Linux kernel
Corpus path
drivers/pwm/pwm_th1520.rs
Extension
.rs
Size
11077 bytes
Lines
367
Domain
Driver Families
Bucket
drivers/pwm
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct Th1520WfHw {
    period_cycles: u32,
    duty_cycles: u32,
    ctrl_val: u32,
    enabled: bool,
}

/// The driver's private data struct. It holds all necessary devres managed resources.
#[pin_data(PinnedDrop)]
struct Th1520PwmDriverData {
    #[pin]
    iomem: devres::Devres<IoMem<'static, TH1520_PWM_REG_SIZE>>,
    clk: Clk,
}

impl pwm::PwmOps for Th1520PwmDriverData {
    type WfHw = Th1520WfHw;

    fn round_waveform_tohw(
        chip: &pwm::Chip<Self>,
        _pwm: &pwm::Device,
        wf: &pwm::Waveform,
    ) -> Result<pwm::RoundedWaveform<Self::WfHw>> {
        let data = chip.drvdata();
        let mut status = 0;

        if wf.period_length_ns == 0 {
            dev_dbg!(chip.device(), "Requested period is 0, disabling PWM.\n");

            return Ok(pwm::RoundedWaveform {
                status: 0,
                hardware_waveform: Th1520WfHw {
                    enabled: false,
                    ..Default::default()
                },
            });
        }

        let rate_hz = data.clk.rate().as_hz() as u64;

        let mut period_cycles = ns_to_cycles(wf.period_length_ns, rate_hz).min(u64::from(u32::MAX));

        if period_cycles == 0 {
            dev_dbg!(
                chip.device(),
                "Requested period {} ns is too small for clock rate {} Hz, rounding up.\n",
                wf.period_length_ns,
                rate_hz
            );

            period_cycles = 1;
            status = 1;
        }

        let mut duty_cycles = ns_to_cycles(wf.duty_length_ns, rate_hz).min(u64::from(u32::MAX));

        let mut ctrl_val = TH1520_PWM_CONTINUOUS_MODE;

        let is_inversed = wf.duty_length_ns > 0
            && wf.duty_offset_ns > 0
            && wf.duty_offset_ns >= wf.period_length_ns.saturating_sub(wf.duty_length_ns);
        if is_inversed {
            duty_cycles = period_cycles - duty_cycles;
        } else {
            ctrl_val |= TH1520_PWM_FPOUT;
        }

        let wfhw = Th1520WfHw {
            // The cast is safe because the value was clamped with `.min(u64::from(u32::MAX))`.
            period_cycles: period_cycles as u32,
            duty_cycles: duty_cycles as u32,
            ctrl_val,
            enabled: true,
        };

        dev_dbg!(
            chip.device(),
            "Requested: {}/{} ns [+{} ns] -> HW: {}/{} cycles, ctrl 0x{:x}, rate {} Hz\n",
            wf.duty_length_ns,
            wf.period_length_ns,
            wf.duty_offset_ns,
            wfhw.duty_cycles,
            wfhw.period_cycles,
            wfhw.ctrl_val,
            rate_hz
        );

        Ok(pwm::RoundedWaveform {
            status,
            hardware_waveform: wfhw,

Annotation

Implementation Notes