General Purpose I/O
General Purpose I/O or GPIO refers to a digital signal from a processor or peripheral capable of sinking or sourcing current.
There are several details that are important when dealing with GPIOs:
- voltage they drive to or are pulled up to
- is there a pull-up or pull-down present
- are they driving to a active-high or active-low state (totem-pole) or are they driving low and relying on a pull-up to go high (open collector)
- how much current can they sink
- how much current can they source
- what bus is used to access them (which can affect when/where and how-fast you can read or write them)
- does the gpio have an associated interrupt available (important if you want to use this as a low-overhead input)
Gateworks boards use General Purpose Input / Output (GPIO) pins commonly for things such as:
- enabling/disabling of devices (ie serial drivers)
- signal steering (ie steer USB bus between front-panel connector/header and PCI/PCIe slot)
- device interrupt inputs (ie GSC host interrupt)
- misc inputs (ie GPS PPS (pulse-per-second) input)
- LED drivers (these are handled via led-class and not gpio-class)
- pushbutton inputs (often handled via button-class and not gpio-class)
All off-board GPIO signals use 3.3V TTL voltage levels.
See the following pages for hardware-specific details and capabilities of the off-board digital I/O pins on the various Gateworks product families:
Power-on GPIO states
Usually these signals are used in such a way that the default power-on state requires no configuration of GPIO signals (ie, the power up state matches the desired power-on function).
As customer needs vary, power-on GPIO states may vary. There are a few options for configuring GPIO's that need to be changed from the 'hardware default':
- bootloader configuration (occurs within milliseconds of board power-up)
- kernel configuration (occurs within seconds of board power-up)
- userspace configuration (occurs within 10s of seconds of board power-up)
- typically this would be done inside of an /etc/rc.local script or other init script. See OpenWrt/init and Yocto/services for more info.
Each of these options requires a different level of software complexity.
Fast vs Slow GPIO
A fast GPIO is one that is directly on the ARM SoC and requires memory mapped register reads and writes to access.
A slow GPIO is one that is provided by a peripheral device that hangs off the SoC on I2C, SPI, USB, or other type of bus that requires complicated bus access mechanisms. These GPIO's are also defined by the linux kernel as GPIO's that 'can sleep' and are not suitable for certain applications that require low latency or deterministic access times in the Linux kernel or in your application usage.
Gateworks products offer a bit of variety:
- all GPIO's provided by the Gateworks System Controller (including the user pushbutton) are over I2C are slow gpio
- Ventana boards have up to 4x DIO's to a connector that are ARM based fast GPIO's
- GPIO's going to the miniPCI and miniPCIe connectors such as WDIS# and PERST# are ARM based fast GPIO's
You can look at the output of /sys/kernel/debug/gpio to see what GPIO's are available and from what controller. The controller name will indicate if its an I2C controller or not.
GPIO mapping
The various product hardware manuals will call out GPIO devices on the board and provide a table mapping the GPIO to a GPIO host controller, a function, and a connector pinout (if going off-board).
This hardware mapping is defined in the following files depending on board/family:
- Venice: Linux kernel device-tree https://github.com/Gateworks/linux-venice/tree/v5.15.15-venice/arch/arm64/boot/dts/freescale
- Newport: Linux kernel device-tree (ie http://github.com/Gateworks/dts-newport)
- Ventana: Linux kernel device-tree (ie arch/arm/boot/dts/imx6qdl-gw54xx.dtsi)
Product Family specific notes:
- Venice:
- See venice/DigitalIO
- Newport:
- CN80XX GPIOs: The CN80XX has one 48bit GPIO controller
- GPIO[0-48]: gpio-464 to gpio-511
- CN80XX GPIOs: The CN80XX has one 48bit GPIO controller
- Ventana:
- IMX6 GPIOs: The IMX6 has 7 32bit GPIO controllers for a possible 224 fast ARM based GPIO's
- GPIO1_IO[0-31]: gpio0-gpio31
- GPIO2_IO[0-31]: gpio32-gpio63
- GPIO3_IO[0-31]: gpio64-gpio95
- GPIO4_IO[0-31]: gpio96-gpio127
- GPIO5_IO[0-31]: gpio128-gpio159
- GPIO6_IO[0-31]: gpio160-gpio191
- GPIO7_IO[0-31]: gpio192-gpio223
- GSC GPIOs:
- GSC_GPIO_P0[0-7]: gpio240-gpio247
- GSC_GPIO_P1[0-7]: gpio247-gpio255
- Additional i2c based GPIO port-expanders present on some boards would begin at gpio116
- IMX6 GPIOs: The IMX6 has 7 32bit GPIO controllers for a possible 224 fast ARM based GPIO's
Note that the Linux gpio mapping is not guaranteed to remain constant across kernel versions. Care should be taken to consult /sys/kernel/debug/gpio
and /sys/class/gpio
when changing kernel versions.
Hardware to Linux Software Conversion
When referring to Gateworks board user hardware manuals you will need to translate the hardware pin name to a gpio using the information above. Some examples:
- Newport GPIO8 would be the 8th IO on the CN80XX GPIO controller thus map to gpio-472.
- Ventana GPIO[1]:DIO16 is GPIO block 1 IO 16 thus maps to gpio0 + 16 (or 0*32+16) = gpio-16
- Ventana GPIO[2]:DIO9 is GPIO block 2 IO 9 thus maps to gpio32 + 9 (or 1*32+9) = gpio-41
- Equation: Venice GPIO<x>IO<y> is GPIO block x IO y thus maps to: gpio-((x-1)*32)+y
- Example chart:
Examples:
- If libgpiod is installed (gpiod package in Ubuntu) the
gpioinfo
app will show you all gpio controllers and details about the GPIO lines each one offers. Note that using the Linux GPIO character device API and/or libgpiod is the preferred way to access GPIO in userspace:root@bionic-newport:~/libgpiod# gpioinfo gpiochip0 - 48 lines: line 0: unnamed unused input active-high line 1: unnamed unused input active-high line 2: unnamed unused input active-high line 3: unnamed unused input active-high line 4: unnamed "interrupt" input active-high [used] line 5: unnamed unused input active-high line 6: unnamed unused input active-high line 7: unnamed unused input active-high line 8: unnamed "mmc_supply_3v3" output active-high [used] line 9: unnamed unused input active-high line 10: unnamed unused output active-high line 11: unnamed unused input active-high line 12: unnamed unused input active-high line 13: unnamed unused input active-high line 14: unnamed "user2" output active-high [used] line 15: unnamed unused output active-high line 16: unnamed unused output active-high line 17: unnamed unused output active-high line 18: unnamed unused output active-high line 19: unnamed unused output active-high line 20: unnamed unused input active-high line 21: unnamed unused input active-high line 22: unnamed unused input active-high line 23: unnamed unused output active-high line 24: unnamed unused input active-high line 25: unnamed unused input active-high line 26: unnamed unused input active-high line 27: unnamed unused input active-high line 28: unnamed unused output active-high line 29: unnamed unused input active-high line 30: unnamed "pps-gpio" input active-high [used] line 31: unnamed "user1" output active-high [used] line 32: unnamed unused input active-high line 33: unnamed unused input active-high line 34: unnamed unused input active-high line 35: unnamed unused input active-high line 36: unnamed unused input active-high line 37: unnamed unused input active-high line 38: unnamed unused input active-high line 39: unnamed unused input active-high line 40: unnamed unused input active-high line 41: unnamed unused input active-high line 42: unnamed unused input active-high line 43: unnamed unused input active-high line 44: unnamed unused input active-high line 45: unnamed unused input active-high line 46: unnamed unused input active-high line 47: unnamed unused input active-high gpiochip1 - 16 lines: line 0: unnamed unused output active-high line 1: unnamed unused input active-high line 2: unnamed "user_pb" input active-low [used] line 3: unnamed unused input active-high line 4: unnamed unused input active-high line 5: unnamed unused input active-high line 6: unnamed unused input active-high line 7: unnamed unused input active-high line 8: unnamed unused input active-high line 9: unnamed unused input active-high line 10: unnamed unused input active-high line 11: unnamed unused input active-high line 12: unnamed unused input active-high line 13: unnamed unused input active-high line 14: unnamed unused input active-high line 15: unnamed unused input active-high
- If debugfs is enabled in the kernel and mounted (as it is on Gateworks BSP's) you can see a nice table of
sysfsgpio
GPIO mapping via/sys/kernel/debug/gpio
. Some examples:- Newport GW6400:
# cat /sys/kernel/debug/gpio gpiochip1: GPIOs 448-463, parent: i2c/0-0023, pca9555, can sleep: gpiochip0: GPIOs 464-511, parent: pci/0000:00:06.0, gpio_thunderx: gpio-472 ( |mmc_supply_3v3 ) out hi gpio-478 ( |user2 ) out lo gpio-495 ( |user1 ) out lo
- Ventana GW5400:
# cat /sys/kernel/debug/gpio GPIOs 0-31, platform/209c000.gpio, 209c000.gpio: gpio-26 (pps-gpio ) in lo gpio-29 (PCIe reset ) out lo gpio-30 (phy-reset ) out hi GPIOs 32-63, platform/20a0000.gpio, 20a0000.gpio: GPIOs 64-95, platform/20a4000.gpio, 20a4000.gpio: gpio-86 (usb_otg_vbus ) out lo GPIOs 96-127, platform/20a8000.gpio, 20a8000.gpio: gpio-102 (user1 ) out lo gpio-103 (user2 ) out lo gpio-111 (user3 ) out lo GPIOs 128-159, platform/20ac000.gpio, 20ac000.gpio: GPIOs 160-191, platform/20b0000.gpio, 20b0000.gpio: GPIOs 192-223, platform/20b4000.gpio, 20b4000.gpio: gpio-192 (2198000.usdhc cd ) in hi GPIOs 240-255, i2c/0-0023, pca9555, can sleep: gpio-240 (user_pb ) in hi
- Note that this does not show GPIO's that are not used by Linux drivers such as USB HUB reset, Ethernet PHY reset, etc.
- Newport GW6400:
See also:
GPIO performance
GPIO performance in terms of latency and frequency at which you can toggle them depends on the GPIO Controller (ie IMX6 SoC ARM GPIO, OcteonTX SoC ARM GPIO, PCA9555 I2C GPIO, FTDI USB UART GPIO) as well as the API used to direct them (ie gpio chardev, sysfsgpio, or direct memory registers in the case of SoC GPIO controllers).
Here is a table showing some max frequencies that GPIO's can be toggled across different platforms:
Controller | API | Speed | Notes |
---|---|---|---|
IMX6DL@800Mhz ARM GPIO | sysfsgpio | 46.3kHz | |
chardev | 140kHz | ||
registers | 870kHz | ||
IMX6DL@800MHz FTDI GPIO | sysfsgpio | 1.0kHz | GPIO over USB |
chardev | 1.33kHz | GPIO over USB | |
IMX6Q@1000Mhz ARM GPIO | sysfsgpio | 73kHz | |
chardev | 255kHz | ||
registers | 805kHz | not clear why this was slower than IMX6DL@800MHz | |
OcteonTX-Dual@800MHz ARM GPIO | sysfsgpio | 200kHz | 4x faster than IMX6DL@800Mhz |
chardev | 580MHz | 4x faster than IMX6DL@800Mhz | |
OcteonTX-Quad@1500MHz ARM GPIO | sysfsgpio | 375kHz | |
chardev | 1.08MHz | 2.8X faster than | |
OcteonTX-Quad@1500MHz FTDI GPIO | sysfsgpio | 5.4kHz | GPIO over USB |
chardev | 6.2kHz | GPIO over USB | |
- The above tests were changing the output value of a GPIO between 0 and 1 (not evaluating time it took to change between input/output direction)
- Note that the FT231X and FT232H were evaluated for FTDI gpio and both performed identically (despite the FT231X being a USB full speed device and the FT232H being a USB high speed device)
- Note that same speed OcteonTX SoC GPIO performs ~4x faster than same speed IMX6
- Note that GPIO chardev is the recomended kernel API for GPIO as sysfsgpio is now deprecated
- GPIO performance over I2C (ie PCA9555) was not evaluated
Linux GPIO
Click here for an in depth introduction to Linux GPIO
chardev GPIO
The GPIO character device ABI (Application Binary Interface) was introduced in Linux 4.8 (which subsequently marked the User-mode sysfsgpio method deprecated). This is a 'descriptor-based' character device exposed as /dev/gpiochipN
or /sys/bus/gpiochipN
where N is the chip number.
The main feature of this new interface is a discovery mechanism which aids in having to figure out where a particular GPIO was mapped. It also supports open-drain I/O support and the ability to read and set multiple I/O lines at once. The downside to this interface is that it prevents manipulating GPIO with standard command line tools such as echo and cat.
Fortunately the kernel is distributed with three basic user-mode tools written for testing the interface which also show examples of the API. These can be found in the kernel source tools/gpio:
- lsgpio - example showing how to list the GPIO lines on a system
- gpio-event-mon - example showing how to monitor GPIO line events from userspace
- gpio-hammer - example swiss army knife to wiggle GPIO lines
Additionally libgpiod provides both API calls for use in your own programs and the following user-mode apps to manipulate GPIO lines:
- gpiodetect - list all gpiochips present on the system, their names, labels and number of GPIO lines
- gpioinfo - list all lines of specified gpiochips, their names, consumers, direction, active state and additional flags
- gpioget - read values of specified GPIO lines
- gpioset - set values of specified GPIO lines, potentially keep the lines exported and wait until timeout, user input or signal
- gpiofind - find the gpiochip name and line offset given the line name
- gpiomon - wait for events on GPIO lines, specify which events to watch, how many events to process before exiting or if the events should be reported to the console
On Ubuntu libgpiod
and its apps can be installed via the gpiod
package:
apt install gpiod
Note that gpioset
(and all libgpiod apps) will revert the state of a GPIO line back to its original value when it exits. For this reason if you want the state to persist you need to instruct gpioset
to wait for a signal and optionally detach and run in the background.
Examples (Venice):
- Finding DIO1 and setting it to output 1 until process is killed (no background)
# gpioinfo | grep dio line 7: "dio0" unused input active-high line 9: "dio1" unused input active-high # gpiofind "dio1" gpiochip0 9 # gpioset --mode signal gpiochip0 9=1
- Note that once gpioset exits its process the GPIO's it changed will revert back to their prior state (by design) therefore we run it above with
--mode=signal
telling it to continue to run into it receives a signal and (optinally)--background
telling it to detach from the controlling terminal to give our shell back. Another process cannot take control of the GPIO if it is being controlled already.
- Note that once gpioset exits its process the GPIO's it changed will revert back to their prior state (by design) therefore we run it above with
- Use gpiofind/gpioget/gpioset on the GPIO named 'pci_wdis#' to drive it low indefinitely (background mode)
# gpiofind pci_wdis# gpiochip3 7 # gpioget gpiochip3 7 1 # gpioset --mode=signal --background gpiochip3 7=0
- in background mode the
gpioset
command continues to run in the background but can be killed via a SIGKILL or SIGTERM which will restore the GPIO to its original state and exit the process
- in background mode the
- Finding M2_OFF# and driving it low (asserting it) momentarily for 10ms then releasing it (de-asserting it)
# gpiofind m2_off# gpiochip3 2 # gpioget gpiochip3 2 1 # gpioset --mode=time --usec 10000 gpiochip3 2=0
}}}
References:
- https://elinux.org/images/9/9b/GPIO_for_Engineers_and_Makers.pdf
- https://kernel.googlesource.com/pub/scm/libs/libgpiod/libgpiod/+/v0.2.x/README.md
Controlling DIO pins with a script or C
Gateworks SBCs have many exposed GPIO pins through headers, but only a few of them are DIO pins which can be controlled by a userspace program and connected to outside electronics, e.g. a LED.
Note: Most of the exposed GPIO pins have special purposes to communicate with peripherals. Most of the internal GPIOs (from gpioinfo) are not connected internally and can be ignored.
Before connecting any outside electronics to a GPIO pin, refer to the hardware manual for your exact device to avoid any damages.
Examples (Venice):
- Blink a LED using a script
#!/bin/bash #Use gpiofind to locate chip & line of DIO0 DIO0=$(gpiofind dio0) status=0 while true; do gpioset --mode=time --sec=1 $DIO0=$status #gpioset holds the line for 1 second status=$((1-status)) #Status (LED) is inverted echo $DIO0 is set to $status done
- Blink a LED using C (Board specific)
#include <gpiod.h> //Requires gpiod to compile #include <stdio.h> #include <unistd.h> int main(int argc, char **argv) { const char* chip_name = "gpiochip0"; const int gpio_line = 7; //DIO0 on GW7201; see gpiofind command struct gpiod_chip* chip = gpiod_chip_open_by_name(chip_name); struct gpiod_line* line = gpiod_chip_get_line(chip, gpio_line); gpiod_line_request_output(line, "blink", 0); int status = 0; while(true){ gpiod_line_set_value(line, status); printf("%s %d set to %d\n", chip_name, gpio_line, status); sleep(1); status = 1-status; } return 0; }
- Both programs make the desired pin output 3.3v and 0v for a second each.
- Refer to https://kernel.googlesource.com/pub/scm/libs/libgpiod/libgpiod/+/v0.2.x/README.md for more info.
User-mode GPIO class
The Linux kernel can provide gpio functionality to userspace via a gpio class accessed via sysfs (/sys/class/gpio/) implemented through gpiolib (CONFIG_GPIOLIB, drivers/gpio/gpiolib*). For userspace access this requires sysfs kernel support (CONFIG_SYSFS) and the sysfs filesystem mounted which is standard for most linux systems including the Gateworks BSP's. This framework allows boards to define GPIO configuration (direction, direction-changeable, user-friendly name, state, and userspace configurable).
Note that the 'sysfsgpio' API has been marked deprecated in Linux 4.8 as the new preferred API is the chardev GPIO API
Note that any gpio that is registered for use by a driver is not available for exporting for userspace control. You can cat /sys/kernel/debug/gpio to see what gpio's are current registered with the kernel.
Here are some example use cases for using gpio-class via sysfs:
- to see gpio names, config (direction), and current state: (requires debugfs kernel support and fs mounted)
cat /sys/kernel/debug/gpio
- to determine the Linux GPIO for a specific offset of a controller you can look for GPIO controller devices that match the bus address of the controller you are interested in. For example if you are trying to find the Linux gpio for the 3rd gpio of an i2c based GPIO controller on i2c0@0x23:
bus="0-0023" for i in $(ls -1d /sys/class/gpio/gpiochip*); do \ [ "$1" = "$(basename $(readlink $i/device))" ] && base=$(cat $i/base); done gpio=$((base+3))
- to export a GPIO that is available to userspace (ie provided by a gpio controller, not in-use by a kernel driver, and not already exported):
echo 5 > /sys/class/gpio/export # export gpio5 (will create /sys/class/gpio/gpio5 and configure as input) echo out > /sys/class/gpio/gpio5/direction # make it an output echo 1 > /sys/class/gpio/gpio5/value # set its value to high
- to see the direction of a gpio via sysfs (only allowed for GPIO's configured as bi-directional)
cat /sys/class/gpio/gpio5/direction ;# in/out
- to set the direction of a gpio via sysfs (only allowed for GPIO's configured as bi-directional)
echo out > /sys/class/gpio/gpio5/direction ;# set as output echo in > /sys/class/gpio/gpio5/direction ;# set as input
- to see the state of a gpio via sysfs
cat /sys/class/gpio/gpio5/value ;# show current state (0=low, any other value than 0=high)
- to set the state of a gpio via sysfs
echo 0 > /sys/class/gpio/gpio5/value ;# assert low echo 1 > /sys/class/gpio/gpio5/value ;# assert high
Detecting GPIO changes efficiently using interrupts
It is extremely inefficient to have an user-mode application that continually checks a GPIO to see if it has changed value as this chews up CPU resources and increases the latency in acting on a GPIO.
Fortunately it is easy to write applications that utilize interrupts as long as the GPIO has an interrupt controller and handler.
chardev GPIO
The GPIO character device API (Application Programming Interface) introduced in Linux 4.8 provides a method of efficiently monitor for interrupt based GPIO changes. This is showing in a couple of readily available examples:
Examples:
sysfsgpio
Note that the sysfsgpio
ABI is deprecated as of Linux 4.8 and it is recommended you using the chardev based GPIO ABI instead
A gpio that has an interrupt associated with it (which depends on the gpio controller and how its hooked up to the processor) can be used with a blocking poll system call. This may seem non-intuitive that you use a 'poll' call to block until an interrupt has occurred, but that is exactly what will happen when you use poll on the sysfs 'value' file representing the value of the gpio in question. Note that even if you are not interested in the value files contents (e.g. counting the total number of interrupts caused by a gpio) you must use both an lseek and a read after poll to consume the interrupt. Otherwise the previous interrupt will cause future poll calls to immediately return.
Note that you can only do this with an GPIO that has interrupt support which means when its exported to userspace there will be an 'edge' file in this /sys/class/gpio directory.
Example code:
/* * gpio-poll.c - demonstrate catching a GPIO change event without polling * ironically using the poll(2) system call * * Author: Tim Harvey <tharvey@gateworks.com> */ #include <fcntl.h> #include <poll.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #ifdef __ANDROID__ #include <cutils/android_reboot.h> #else #include <sys/reboot.h> #endif #include <sys/types.h> #include <sys/stat.h> int main(int argc, char **argv) { struct pollfd fdset; char path[256]; char buf[32]; int gpio; int fd, rz, c; if (argc < 3) { fprintf(stderr, "usage: %s <gpio> <rising|falling|both>\n", argv[0]); exit (-1); } gpio = atoi(argv[1]); /* configure gpio trigger: * edge trigger of 'both' (falling and rising) allows catching * changes in both directions vs level triggerd. */ sprintf(path, "/sys/class/gpio/gpio%d/edge", gpio); if ((fd = open(path, O_WRONLY)) < 0) { perror("open() failed\n"); fprintf(stderr, "non-exported or non-input gpio: %s\n", path); exit (-1); } write(fd, argv[2], strlen(argv[2])); close(fd); /* open gpio sysfs value for reading in blocking mode */ sprintf(path, "/sys/class/gpio/gpio%d/value", gpio); if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0) { perror("open() failed\n"); fprintf(stderr, "invalid or non-exported gpio: %s\n", path); exit (-1); } printf("monitoring %s for interrupt using poll()\n", path); while (1) { /* use poll(2) to block for 10s or until interrupt occurs */ fdset.fd = fd; fdset.events = POLLPRI; fdset.revents = 0; if ((c = poll(&fdset, 1, -1)) < 0) { perror("poll() failed"); break; } /* show gpio value */ /* Note that both an lseek and read are necessary * in order to clear the interrupt detected by poll */ usleep (100000); /*100ms delay to debounce*/ lseek(fd, 0, SEEK_SET); rz = read(fd, buf, sizeof(buf)); buf[rz ? rz - 1 : 0] = 0; printf("%d: ret=%d gpio%d=%d rz=%d\n", (int)time(NULL),c, gpio, atoi(buf), rz); } close(fd); return 0; }
Example usage (block until interrupt rising and falling edge interrupt occurs on gpio-100):
root@OpenWrt:/# ./gpio-poll 100 both monitoring /sys/class/gpio/gpio100/value for interrupt using poll() gpio100: 1 gpio100: 0 gpio100: 1 gpio100: 0 gpio100: 1
using GPIO's as buttons in Linux
Often users want to use a GPIO as a button. The best way to do this in Linux is to use the gpio-keys (KEYBOARD_GPIO) or gpio-keys-polled (KEYBOARD_GPIO_POLLED) Linux input driver which allows you to assign Linux gpio's to Linux input key events which will be fired when the button is pressed and released.
The gpio-keys driver is for gpio's that are interrupt capable and the gpio-keys-polled driver is for gpio's that are not interrupt capable and thus must be polled periodically.
As an example of how to configure the gpio-keys driver we can look at the GW51xx which has DIO0-DIO4 mapped to ARM gpio's. The imx6qdl-gw51xx.dtsi device-tree can have the following section added:
/* define linux keyboard gpio-keys driver named 'gpio-button' */ gpio: gpio-button { compatible = "gpio-keys"; #address-cells = <1>; #size-cells = <0>; autorepeat; /* map GW51xx DIO0 IMX6 GPIO1_IO16 to linux keycode 103 (KEY_UP) */ button@1 { label = "GPIO Key Up"; linux,code = <103>; debounce-interval = <100>; gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; }; /* map GW51xx DIO1 IMX6 GPIO1__IO19 to linux keycode 109 (KEY_DOWN) */ button@2 { label = "GPIO Key Down"; linux,code = <108>; debounce-interval = <100>; gpios = <&gpio1 19 GPIO_ACTIVE_LOW>; }; /* map GW51xx DIO2 IMX6 GPIO1__IO17 to linux keycode 106 (KEY_RIGHT) */ button@3 { label = "GPIO Key Right"; linux,code = <106>; debounce-interval = <100>; gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; }; /* map GW51xx DIO3 IMX6 GPIO1__IO18 to linux keycode 105 (KEY_LEFT) */ button@4 { label = "GPIO Key Left"; linux,code = <105>; debounce-interval = <100>; gpios = <&gpio1 18 GPIO_ACTIVE_LOW>; }; };
- The gpio node needs to be at the top level and its placement is arbitrary however its customary to put it in alphabetical order (thus between the chosen node and the leds node)
BSP Specific notes:
- OpenWrt replaces the gpio-keys and gpio-keys-polled Linux driver with their out-of-tree driver called gpio-button-hotplug which instead of emiting linux input events emits uevent messages to the button subsystem which tie into the OpenWrt hotplug daemon. See the OpenWrt/gpio page for more details.
- Android can map Linux input events to Android key events via a KeyLayout file - see here for details.
References
- gpio-keys driver and device-tree bindings
- gpio-keys-polled driver and device-tree bindings
U-Boot GPIO
The U-Boot bootloader has basic support for GPIO's associated with a driver (such as processor GPIO's):
Examples:
- Show GPIO's
u-boot=> gpio status Bank GPIO1_: GPIO1_0: output: 0 [x] rs485_term.gpio-hog GPIO1_1: input: 0 [x] mipi_gpio4.gpio-hog GPIO1_6: output: 0 [x] pci_usb_sel.gpio-hog GPIO1_7: input: 1 [x] dio0.gpio-hog GPIO1_9: input: 1 [x] dio1.gpio-hog Bank GPIO2_: GPIO2_12: input: 1 [x] mmc@30b50000.cd-gpios Bank GPIO3_: GPIO3_0: output: 0 [x] ethernet@30be0000.phy-reset-gpios Bank GPIO4_: GPIO4_0: output: 0 [x] rs485_en.gpio-hog GPIO4_1: input: 0 [x] mipi_gpio3.gpio-hog GPIO4_2: output: 0 [x] rs485_hd.gpio-hog GPIO4_3: input: 0 [x] mipi_gpio2.gpio-hog GPIO4_4: input: 0 [x] mipi_gpio1.gpio-hog GPIO4_7: output: 1 [x] pci_wdis#.gpio-hog Bank GPIO5_: GPIO5_4: output: 0 [x] led-1.gpios GPIO5_5: output: 0 [x] led-0.gpios
- show status of a particular GPIO (using the gpio id reported above)
u-boot=> gpio status GPIO4_7 Bank GPIO4_: GPIO4_7: output: 1 [x] pci_wdis#.gpio-hog u-boot=> gpio status GPIO1_7 Bank GPIO1_: GPIO1_7: input: 1 [x] dio0.gpio-hog u-boot=>
- above you can see that GPIO4_7 (the 'pci_wdis#' gpio on this board) is an output and currently driven high
- above you can see that GPIO1_7 (the 'dio0' gpio on this board) is an input and its current value is high
- note that a 0 always represents a voltage low and 1 always represents a voltage high regardless of if the gpio is considered 'active high' or 'active low' (which is typically indicated by the GPIO name as active low gpios typically end with a '#')
- set a gpio to output low (clr)
u-boot=> gpio clr GPIO4_7 gpio: pin GPIO4_7 (gpio 103) value is 0
- set a gpio to output high (set)
u-boot=> gpio set GPIO4_7 gpio: pin GPIO4_7 (gpio 103) value is 1
- toggle gpio:
u-boot=> gpio toggle GPIO4_7 gpio: pin GPIO4_7 (gpio 103) value is 0 u-boot=> gpio toggle GPIO4_7 gpio: pin GPIO4_7 (gpio 103) value is 1
The value specified to the vaious gpio commands can be one of:
- bank name (ie GPIO4_ above) to represent all GPIO's in that bank
- pin name (ie GPIO4_7 above) to represent a specific gpio
- pin number (ie 103) to represent a specific gpio. The pin number notation is not recommended as it depends on GPIO controllers being registered in the same order which may not always be the case. It is always better to refer to the bank and pin name/notation.
Note that on some platforms GPIO's can not be read back unless configured a specific way. This is the case on IMX boards where GPIO cells need to have the 'Software Input On' (SION) bit enabled in order to read it back. If you have such as GPIO you can still drive it high but you will get a wraning such as 'Warning: value of pin is still 0'. Additinally the 'toggle' won't function for these GPIO's as the software can't determine what state they are.
Notable GPIO's on Gateworks boards
Gateworks boards use GPIO control for various things including:
- General Purpose off-board GPIO/PWM
- on-board LED's
- Various enables for add-in cards
GPIO for LED's
SoC based GPIO's are often used for LED's on various Gateworks boards.
For Linux the gpio-led
driver supports GPIO based LED's which has a sysfs interface for manipulating the LED's in Linux:
- see wiki:linux/led
For U-Boot the gpio-led
driver is partially supported in U-Boot proper (heartbeat trigger is currently not supported in U-Boot but LED's will be enabled). There is no LED support currently in the U-Boot SPL so if your board uses U-Boot SPL and you want LED support earlier in the boot process you need to add GPIO configuration to an early function such as board_init_f().
W_DISABLE#
The W_DISABLE# pin (aka WLAN_DIS#) is a pin on miniPCIe cards that if implemented disable radio operation according to the spec. In reality some radios use this as a GPIO that a radio driver can read and certain devices such as the WLE900VX ath10k 802.11 WiFi radio will not even enumerate on the PCIe bus if this is driven low.
Board | GPIO pin/cont | GPIO offset | Linux GPIO | Notes |
---|---|---|---|---|
GW700x | GPIO4_IO7 GPIO4 | 7 | gpio103 | (in bootloader) gpio set 103 |
GW6xxx | GSC P0.0 i2c/0-0023 | 0 | gpio448 | This is a GSC gpio |
GW54xx | GPIO5_IO17 GPIO5 | 17 | gpio145 | ventana U-Boot drives this high by default |
GW53xx | GPIO7_IO12 | 12 | gpio209 | ventana U-Boot drives this high by default |
GW52xx | GPIO7_IO12 | 12 | gpio209 | ventana U-Boot drives this high by default |
GW51xx | GPIO7_IO12 | 12 | gpio209 | ventana U-Boot drives this high by default |
GW551x | GPIO7_IO12 | 12 | gpio209 | ventana U-Boot drives this high by default |
GW552x | GPIO7_IO12 | 12 | gpio209 | ventana U-Boot drives this high by default |
GW553x | GPIO7_IO12 | 12 | gpio209 | ventana U-Boot drives this high by default |
GW5910 | GPIO1_IO0 | 0 | gpio0 | ventana U-Boot drives this high by default |
GW5913 | GPIO1_IO0 | 0 | gpio0 | ventana U-Boot drives this high by default |
In most cases shown by the table above the GPIO above will be defaulted to driven high in boot firmware or have a pull-up on the card thus typically you would only need to make a change if you want to drive the signal low to 'assert' W_DISABLE# (to disable the card's RF output).
Other References
Here are some other useful references from our wiki:
Attachments (2)
-
gpio.txt
(6.1 KB
) - added by 6 years ago.
GPIO.txt
- gpio.png (86.4 KB ) - added by 8 months ago.
Download all attachments as: .zip