GPIO for Engineers and Makers – Linus Walleij

Linus is the maintainer of the GPIO subsystem. What has happened since the gpiolib subsystem was introduced in 2006?

At the time, GPIO was considered as something very specific for weird platforms. It was invented for SoCs that had a few lines of GPIO. It was conceived for a single GPIO controller. Maintenance was taken over by Grant Likely in 2011 when the original author (David) fell ill. Taken over by Linus in 2012, because it is related to pinctrl which is Linus’s domain.

GPIO is not really simple.

GPIOLIB is now a directly selectable symbol, it doesn’t have arch dependencies anymore.

Much of the changes in recent years come out of the ARM cleanup: moving things from platform code to drivers, and getting rid of global number spaces.

New concept: GPIO descriptor gpio_desc, instead of just a number. Now you use (devm_)gpiod_get(dev, “reset”, GPIOD_OUT_LOW) to request a GPIO for device dev. It looks for GPIOs by name (relative to dev) instead of by number. This comes out of DT, ACPI or board files. By requesting it, it is bound to the device.

gpio is now a real device struct gpio_device with an embedded struct device. gpios live in /sys/bus/gpio and there is a chardev as well.

Open drain/collector and open source/emitter support. If the hardware supports this, it is possible to control it from the generic framework. Previously, open drain was emulated by setting the pin to input. It is also possible to generically configure debounce (to some extent). What cannot be set is pullup/down, drive strength, because they are considered pinctrl.

Typically there is a pinctrl driver in the backend of the gpio driver, so there is a mapping between them. They are associated with each other with gpiochip_add_pin_range(). In the gpio driver, call pinctrl with pinctrl_request/free_gpio() (controls muxing) and pinctrl_gpio_direction_in/output() (controls configuration). Maybe there should be one more callback to set pincfg options, but currently there is no use case. Note that it is often possible to use a pin simultaneously for GPIO and for something else.

irqchip integration – CONFIG_GPIOLIB_IRQCHIP. If something is used as an interrupt, you probably don’t want to switch it to an output. gpiochip_(un)lock_as_irq takes care of this. gpiolib_irqchip is a generic implementation of IRQs on GPIOs; the idea is that those things are always controlled by a register that says for each bit if it’s an interrupt. gpiolib_irqchip_add to create the irqchip for a gpiochip; gpiochip_set_changed_irqchip to connect to the parent interrupt.

GPIO hogs preconfigure GPIOs at boot time from the device tree, even if there is no driver that uses that line. E.g. to provide some bias that is expected at the board level, but for which there is no corresponding device so no driver.

Linus says: DO NOT ACCESS GPIOS FROM USERSPACE. For push buttons, for sensors, for bitbanging some bus, etc. write a kernel driver. But there are use cases. For these, there is a character device. sysfs interface doesn’t work because it uses global numbers, and it’s kind of stateless (the export stuff is a hack, when you application crashes it remains exported). The character device has discovery based on strings, cleans up resources when the FD is closed, it supports configuring open drain, you can set/get multiple lines at once. Plenty of examples in tools/gpio.

lspgio says which lines are unused.

GPIO line names are specified in device tree.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s