PWMC(4)

πŸ’– PWMC πŸ’–

okay bestie, gather round, because we're talking about pwmc β€” the PWM (Pulse Width Modulation) control device driver ✨ It lives in the Kernel Interfaces Manual (section 4, for the uninitiated πŸŽ€) and it's literally the thing that lets you talk to your PWM hardware from userspace. no cap.


✨ SYNOPSIS ✨

so like, you got two ways to get this driver into your life, and both are valid πŸ’…

Option A: bake it into the kernel. drop these lines in your kernel config file:

device pwmbus
device pwmc

Option B: load it as a module at boot. put this line in loader.conf(5):

pwmc_load="YES"

pick your fighter, both slay 🫢


🌸 DESCRIPTION 🌸

okay so here's the tea β˜• The pwmc driver gives you device-control access to a channel of PWM hardware. And the way it works? Each individual instance of a pwmc device is tied to exactly one single PWM output channel. one instance, one channel, very monogamous of it πŸ’€

now, some PWM hardware is set up all communal-style, with multiple channels sharing a common clock or other resources πŸ‘― In those cases you'll still get a separate pwmc instance for each channel, BUT β€” and this is the important part, bestie β€” changing the period or duty cycle of any one channel may affect other channels within the hardware that share the same resources 😭 so like, be careful, your backlight might start beefing with your fan. Consult the documentation for the underlying PWM hardware device driver for the deets on which channels share resources. iykyk.

an instance of pwmc creates a character device named /dev/pwm/pwmcX.Y where:

  • X is a sequential number assigned to each PWM hardware controller as it is discovered by the system πŸ”’
  • Y is the channel number within that hardware controller 🎯

and here's the cute part: the driver can be configured to create aliases that point to the pwmcX.Y entries, which is basically giving your channels ✨names✨. named channels. main character energy fr fr.


πŸŽ€ The ioctls πŸŽ€

pwmc gives you control of a PWM channel with these ioctl(2) calls and data structures, all defined in <dev/pwm/pwmc.h>:

  • PWMGETSTATE (struct pwm_state) β€” Retrieve the current state of the channel. it's giving "let me see what you're up to" πŸ‘€
  • PWMSETSTATE (struct pwm_state) β€” Set the current state of the channel. ⚠️ All parameters are updated on every call. so like, every single one. To change just one of the values, use PWMGETSTATE to get the current state and then submit the same data back with just the appropriate value changed. classic get-modify-set, you got this πŸ’ͺ

πŸ¦‹ The pwm_state structure πŸ¦‹

it's defined as follows, and honestly? iconic:

struct pwm_state {
        u_int           period;
        u_int           duty;
        uint32_t        flags;
        bool            enable;
};

let's break it down, bestie:

  • period β€” The duration, in nanoseconds, of one complete on-off cycle. ⏱️
  • duty β€” The duration, in nanoseconds, of the on portion of one cycle. πŸ’‘
  • flags β€” Flags that affect the output signal, and they can be bitwise-ORed together. The following flags are currently defined:
    • PWM_POLARITY_INVERTED β€” Invert the signal polarity. πŸ”„ flip it, reverse it
  • enable β€” false to disable the output signal, or true to enable it. the on/off switch, the moment of truth 🎬

🌈 HINTS CONFIGURATION 🌈

on a device.hints(5) based system (think MIPS, bestie), these values are configurable for pwmc:

  • hint.pwmc.%d.at β€” The pwmbus instance the pwmc instance is attached to. πŸ“Ž
  • hint.pwmc.%d.channel β€” The hardware channel number the instance is attached to. Channel numbers count up from zero. 0️⃣1️⃣2️⃣
  • hint.pwmc.%d.label β€” If this optional hint is set, the driver creates an alias in /dev/pwm with the given name, which points to the instance. 🏷️ cute nickname moment

🧚 FDT CONFIGURATION 🧚

on an fdt(4) based system, a pwmc device is described with a child node of the pwm hardware controller node. and here's a lil shortcut: when the hardware supports multiple channels within the controller, you do not need to include a pwmc child node for every channel the hardware supports. Define only the channels you need to control. efficiency queen πŸ‘‘

the following properties are required for a pwmc device node:

  • compatible β€” Must be the string "freebsd,pwmc". no typos, bestie, it's exact πŸ’…
  • reg β€” The hardware channel number.

the following properties are optional for the pwmc device node:

  • label β€” A string containing only characters legal in a file name. The driver creates an alias with the given name in /dev/pwm which points to the instance's /dev/pwm/pwmcX.Y device entry. 🌸

⭐ Example of a PWM hardware node containing one pwmc child node ⭐

here's what it looks like in the wild, so you can copy the vibe:

&ehrpwm0 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&ehrpwm0_AB_pins>;

    pwmcontrol@0 {
        compatible = "freebsd,pwmc";
        reg = <0>;
        label = "backlight";
    };
};

see how the label is "backlight"? that's the named-channel glow-up in action ✨


πŸ“ FILES πŸ“

  • /dev/pwm/pwmc* β€” where all the magic happens πŸͺ„

πŸ‘‘ SEE ALSO πŸ‘‘

go read these next, they're the whole friend group:


πŸ’œ HISTORY πŸ’œ

The pwmc driver appeared in FreeBSD 13.0. a legend was born πŸŽ‚


πŸ’€ reminder bestie: shared resources mean shared consequences. if you're on multi-channel hardware with a common clock, changing one channel can mess with the others. that's not a vibe, that's a warning. check your hardware driver docs.

and that's the whole page, you're officially pwmc-pilled 🧠✨ this beauty came to us from the Debian corner of the world, dated June 17, 2019, and it's the PWMC(4) page, periodt πŸ’…πŸ«Ά mwah, go modulate some pulses responsibly πŸŒˆπŸŽ€

πŸ“¦ where this page comes from