NXP i.MXRT10XX: Controlling GPIO from Linux User Space
This application note shows how to control the i.MX RT1050/RT1060 GPIOs from the user level using the standard Linux GPIOLIB
interface.
1. Changes to the Kernel Configuration
The generic GPIO interface is controlled by the CONFIG_GPIOLIB
kernel option enabled by default in the rootfs
project. Most of the i.MX RT1050/RT1060 GPIO pins can be used in different multiplexed I/O roles (for instance, some GPIO pins can be also configured as an SPI interface, etc.) Depending on the requirements of your application, you need to configure the pins that you want to use as GPIO for the GPIO role and other pins for an alternative I/O function.
In this application note, we configure the following two pins as GPIO:
GPIO_AD_B0_09 (GPIO1_IO09)
- this pin is connected to theUSER LED
of the IMXRT10XX-EVKB board (refer toD18
on i.MX RT1050-EVKB or to theD8
LED on IMXRT1060-EVKB) and can be used as a GPIO Output to control LEDWAKEUP (GPIO5_IO00)
- this pin is connected to theUSER BUTTON
of the IMXRT10XX-EVKB board (refer toSW8
on IMXRT1050-EVKB orSW5
on IMXRT1060-EVKB) and can be used as a GPIO Input to get status of the button.
Note that there is the pin conflict in design of the NXP's IMXRT10XX-EVK(B) boards: the GPIO_AD_B0_09 pin is connected to both USER LED and to the Ethernet PHY reset line. To avoid conflict in software and allow using GPIO_AD_B0_09 as a regular GPIO, the fec node should be disabled in DTS.
The pin multiplexing, as well as the PAD control specific configuration, is performed by the Linux kernel drivers using the information from the project's DTS
file, this is rootfs.dts.IMXRT105X_NXPEVK
or rootfs.dts.IMXRT106X_NXPEVK
. Let's edit this file and add the information about the above two GPIOs:
Update the
pinctrl_leds
andpinctrl_gpio_key
nodes with the information about specific (e.g. pull-up, alt mux, ...) settings of the used GPIOs.Update the
leds
andgpio-keys
nodes, and specify GPIOs which will be used with them.Disable the
fec
node to freeGPIO_AD_B0_09
from the Ethernet driver.
The result should look like this:
pinctrl_leds: ledsgrp {
fsl,pins = <
MXRT1050_IOMUXC_GPIO_AD_B0_09_GPIO1_IO09 MXRT10XX_PAD_CFG_GPIO
>;
};
pinctrl_keys: keysgrp {
fsl,pins = <
MXRT1050_IOMUXC_SNVS_WAKEUP_GPIO5_IO00 MXRT10XX_PAD_CFG_GPIO
>;
};
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_leds>;
#if 0
/* disbale user-led by deafult due to pinctrl conflict with the FEC device */
status = "disbaled";
user-led {
label = "user-led";
gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
#endif
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_keys>;
#if 0
user-button {
label = "user-button";
gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_A>;
};
#endif
};
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_fec>;
status = "disabled";
...
};
After applying the above changes to the DTS file, rebuild the rootfs
project ( Building Linux ) and install it on the target (Building and Installing Linux uImage on the NXP i.MX RT10XX EVK Board ).
2. Testing GPIO
Each GPIO is assigned a unique integer GPIO number within the GPIO chip range of 0 to 142 by Linux. The i.MX RT1050/1060 supports 5 GPIO blocks (gpio_chips) of 32 pieces GPIO1, GPIO2, GPIO3, GPIO4 and GPIO5. Note that for the GPIO5 chip only 3 first signals are actually available: GPIO5_IO00, GPIO5_IO01 and GPIO5_IO02 - the rest are not output anywhere.
To calculate that number for a specific GPIO, use the following formula:
gpio = chip_base + pin
Kernel allocates the base numbers for GPIO chips dynamically, in 6.6.x the 512 offset is applied to all numbers, refer to include/linux/gpio.h
in the Linux kernel sources:
/*
* At the end we want all GPIOs to be dynamically allocated from 0.
* However, some legacy drivers still perform fixed allocation.
* Until they are all fixed, leave 0-512 space for them.
*/
#define GPIO_DYNAMIC_BASE 512
Since each chip contains the same amount of GPIOs equal to 32, the chip_base
can be calculated as:
So the resultant formula for the GPIO number is:
For example:
gpio number for
GPIO01.IO09
will be (1 – 1) * 32 + 512 + 9 = 521.gpio number for
GPIO05.IO00
will be (5 – 1) * 32 + 512 + 0 = 640.
2.1. Testing USER LED
Export
GPIO1_IO09
:Use the following command to turn on the
USER LED
:Use the following command to turn off the
USER LED
:
2.2. Testing USER BUTTON
Export
GPIO5_IO00
:Make sure the value of
GPIO5_IO00
is 1 when theUSER BUTTON
is untouched (due to the internal PULL-UP being enabled):Press and hold the
USER BUTTON
and make sure theGPIO5_IO00
value has changed to 0:
3. Alternative Ways to Access GPIO
In Linux, you may access GPIOs using different approaches, not only the ones described in this application note above. Here are some external links that might be useful if you decide to try an alternative approach.
The following article describes accessing GPIOs from the kernel context: https://lwn.net/Articles/532714/
To work with GPIOs from the user space, there are the following possibilities:
Using the GPIOLIB interface (described in this application note):
https://www.kernel.org/doc/Documentation/gpio/sysfs.txtUsing the drivers of the Linux LED/Input subsystems:
https://www.kernel.org/doc/Documentation/leds/leds-class.txt
https://www.kernel.org/doc/Documentation/input/input.txt
These drivers allow to use different GPIO-related mechanisms already implemented in Linux. For example, you may simply force a LED connected to GPIO output to blink with the specified frequency,
or simply force input subsystem to generate a some-button-pressed event on changing GPIO input.