Controlling GPIO in Linux Print

 

This application note shows how to control i.MX8M GPIOs in Linux.


Changes to the Kernel Configuration

The generic GPIO interface is controlled by the CONFIG_GPIOLIB kernel option enabled by default in the Emcraft i.MX8M kernel. Most of the i.MX8M 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:

  • SAI2_RXFS - this pin is connected to the BTN1 User Push Button on the IMX8M-SOM-BSB baseboard and, as such, can be used as a GPIO Input.
  • SAI5_RXFS - this pin is connected to the LED1 User LED on the IMX8M-SOM-BSB baseboard and, as such, can be used as a GPIO Output.

The pin multiplexing, as well as the GPIO specific configuration, is performed by the Linux kernel drivers using the information from the meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som.dts file. Let's edit this file and add the information about the above two GPIOs:

  • Delete the current leds and gpio-keys nodes. These implement support for LEDs and buttons.
  • Create the pinctrl_gpios node with the information about specific (e.g. pull-up) settings of the used GPIOs.
  • Create the gpio_init node to initialize GPIOs with necessary (e.g. pull-up) settings (at the CONFIG_KEYBOARD_GPIO driver probe routine).
  • The result should look like this:

/ {
...
gpio_init {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpios>;
};
};

&iomuxc {
imx8m-som {
pinctrl_gpios: gpiogrp {
fsl,pins = <
MX8MQ_IOMUXC_SAI5_RXFS_GPIO3_IO19 0x16
MX8MQ_IOMUXC_SAI2_RXFS_GPIO4_IO21 0x16
>;
};
};
};

After applying the above changes to the meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som.dts file, rebuild the device tree (Building Linux Kernel) and use it to boot the target.


Testing GPIO

Each GPIO is assigned a unique integer GPIO number within the GPIO chip range of 0 to 160 by Linux. To calculate that number for a specific GPIO, use the following formula:

gpio = ((bank - 1) * 32) + pin

Bank numbers start with 1 (corresponding to GPIO1, etc), pin numbers start with 0 (corresponding to pin 0, etc).

For the User Push Button the specific pin is SAI2_RXFS (GPIO4_IO21), which corresponds to the following GPIO number:

((4 - 1) * 32) + 21 = 117

The first step is to add (export) the pin to the GPIO array and define it as an input. This is done as follows:

/ # echo 117 > /sys/class/gpio/export
/ # echo in > /sys/class/gpio/gpio117/direction

Now, all is ready to read the value of the User Push Button. First, leave the button unpressed on the board and read the signal. We enabled pull-up for this GPIO in rootfs.dts.STM32F7 (see the S2.but node), so when the User Push Button unpressed this GPIO reads as 1:

/ # cat /sys/class/gpio/gpio117/value
1

Push the button and make sure the GPIO value reads as 0:

/ # cat /sys/class/gpio/gpio117/value
0

Release the button and validate that the value has returned to 1:

/ # cat /sys/class/gpio/gpio117/value
1

For the User LED the specific pin is SAI5_RXFS (GPIO3_IO19), which corresponds to the following GPIO number:

((3 - 1) * 32) + 19 = 83

Export the GPIO and define it as an output:

/ # echo 83 > /sys/class/gpio/export
/ # echo out > /sys/class/gpio/gpio83/direction

Now run the following shell commands to turn the User LED on and off at a 1Hz frequency:

/ # while [ 1 ]; do echo 1 > /sys/class/gpio/gpio83/value; sleep 1; echo 0 > /sys/class/gpio/gpio83/value; sleep 1; done

Stop this test by pressing Ctrl-C, and run a composite test: control the User LED with the User Push Button (turn the LED on if the Button is unpressed, and turn the LED off if the Button is pressed):

/ # while [ 1 ]; do cat /sys/class/gpio/gpio117/value > /sys/class/gpio/gpio83/value; done


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 usefull if you decide to try an alternative approach.

To work with GPIOs from the user space, there are the following possibilities:

Controlling GPIO from Kernel

The following article describes accessing GPIOs from the kernel context:
https://lwn.net/Articles/532714/

As an example of a device driver that makes use of the kernel GPIO APIs, refer to the device driver for the Goodix touch-screen controller. The device driver configures and uses a GPIO input for interrupt.

The relevant device tree file is meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som-mipi-frd55.dts. Refer specifically to the goodix_ts@5d node and the goodix,irq-gpio property.

The device driver itself is linux/drivers/input/touchscreen/gt1x/gt1x.c. Refer specifically to the gt1x_parse_dt(), gt1x_request_io_port(), and gt1x_request_irq() functions.