fdt_pinctrl(9)

πŸ’– fdt_pinctrl β€” the manual page, but make it make sense πŸ’–

okay bestie, so this is fdt_pinctrl(9), living in the Kernel Developer's Manual section 9, and it's literally the helper-functions situation for FDT pinmux controller drivers. no cap. let's get into it ✨


✨ NAME ✨

fdt_pinctrl β€” helper functions for FDT pinmux controller drivers πŸŽ€


🌸 SYNOPSIS 🌸

#include <dev/fdt/fdt_pinctrl.h>

int
fdt_pinctrl_configure(device_t client, u_int index);

int
fdt_pinctrl_configure_by_name(device_t client, const char * name);

int
fdt_pinctrl_register(device_t pinctrl, const char *pinprop);

int
fdt_pinctrl_configure_tree(device_t pinctrl);

like… look at those signatures. iconic. πŸ‘‘


πŸ’… DESCRIPTION πŸ’…

so fdt_pinctrl(4) gives you an API for manipulating I/O pin configurations on pinmux controllers and pinmux clients. two sides, one vibe.

On the controller side, the standard newbus probe and attach methods are implemented, periodt. As part of handling attach, it calls the fdt_pinctrl_register() function to register itself as a pinmux controller. then fdt_pinctrl_configure_tree() is used to walk the device tree and configure pins specified by the pinctrl-0 property for all active devices. the driver also implements the fdt_pinctrl_configure() method, which lets client devices change their pin configurations after startup β€” like a lil glow-up mid-lifecycle, we love that for them. so if a client device requires a pin configuration change at some point of its lifecycle, it uses the fdt_pinctrl_configure() or fdt_pinctrl_configure_by_name() functions. πŸ¦‹

fdt_pinctrl_configure() is used by client device client to request a pin configuration described by the pinctrl-N property with index index. (N = index, iykyk)

fdt_pinctrl_configure_by_name() is used by client device client to request the pin configuration with name name. yes, by NAME. because sometimes numbers are not the move. πŸ’–

fdt_pinctrl_register() registers a pinctrl driver so that it can be used by other devices which call fdt_pinctrl_configure() or fdt_pinctrl_configure_by_name(). it also registers each child node of the pinctrl driver's node which contains a property with the name given in pinprop. If pinprop is NULL, every descendant node is registered. and β€” plot twist β€” it is possible for the driver to register itself as a pinmux controller for more than one pin property type by calling fdt_pinctrl_register() multiple types. (that's what the original says, and we're not editing the source, bestie. πŸ’€)

fdt_pinctrl_configure_tree() walks through enabled devices in the device tree. If the pinctrl-0 property contains references to child nodes of the specified pinctrl device, their pins are configured. simple as that, no notes. 🌈


πŸ”₯ EXAMPLES πŸ”₯

okay this is the part where it gets real. code time, don't blink:

static int
foo_configure_pins(device_t dev, phandle_t cfgxref)
{
    phandle_t cfgnode;
    uint32_t *pins, *functions;
    int npins, nfunctions;

    cfgnode = OF_node_from_xref(cfgxref);
    pins = NULL;
    npins = OF_getencprop_alloc_multi(cfgnode, "foo,pins", sizeof(*pins),
        (void **)&pins);
    functions = NULL;
    nfunctions = OF_getencprop_alloc_multi(cfgnode, "foo,functions",
        sizeof(*functions), (void **)&functions);
    ...
}

static int
foo_is_gpio(device_t dev, device_t gpiodev, bool *is_gpio)
{
    return (foo_is_pin_func_gpio(is_gpio));
}

static int
foo_set_flags(device_t dev, device_t gpiodev, uint32_t pin, uint32_t flags)
{
    int rv;

    rv = foo_is_pin_func_gpio(is_gpio);
    if (rv != 0)
        return (rv);
    foo_set_flags(pin, flags);
    return (0);
}

static int
foo_get_flags(device_t dev, device_t gpiodev, uint32_t pin, uint32_t *flags)
{
    int rv;

    rv = foo_is_pin_func_gpio(is_gpio);
    if (rv != 0)
        return (rv);
    foo_get_flags(pin, flags);
    return (0);
}

static int
foo_attach(device_t dev)
{
    ...

    fdt_pinctrl_register(dev, "foo,pins");
    /*
     * It is possible to register more than one pinprop handler
     */
    fdt_pinctrl_register(dev, "bar,pins");
    fdt_pinctrl_configure_tree(dev);

    return (0);
}

static device_method_t foo_methods[] = {
    ...

    /* fdt_pinctrl interface */
    DEVMETHOD(fdt_pinctrl_configure, foo_configure_pins),
    DEVMETHOD(fdt_pinctrl_is_gpio, foo_is_gpio),
    DEVMETHOD(fdt_pinctrl_set_flags, foo_set_flags),
    DEVMETHOD(fdt_pinctrl_get_flags, foo_get_flags),

    /* Terminate method list */
    DEVMETHOD_END
};

DRIVER_MODULE(foo, simplebus, foo_driver, foo_devclass, NULL, NULL);

like hello?? the method table ate and left no crumbs. πŸ’… the /* Terminate method list */ + DEVMETHOD_END combo is giving responsible driver energy, and honestly we're obsessed.


πŸ‘€ SEE ALSO πŸ‘€


🫢 AUTHORS 🫢

This manual page was written by Oleksandr Tymoshenko. legend behavior, fr fr. πŸ‘‘


and that's the whole page, bestie!! this one's from the Debian flavor of things, dated June 23, 2018 β€” oldie but a goodie. go configure some pins, you got this πŸ’–βœ¨πŸŽ€πŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from