Search by Tags

GPIO (Linux)

 

Compare with Revision




Subscribe for this article updates

Please note that Pin configuration/muxing is a non-trivial part of the overall system design. It is easily possible to do illegal configurations when it comes to multiplexed pins (e.g. one pin driving low and the other one driving high). Even more though on SoCs where certain settings in this respect can not be done per pin but rather only per pin group.

GPIO Tool

The Toradex GPIO tool can be used to read the current pin configuration or to temporally change the pin configuration and GPIO state. It can either be started from the launcher on the desktop or through the command line as follows:

root@colibri_t20:~$ GPIOConfig

  • Toradex GPIOConfig utility

    Toradex GPIOConfig utility

GPIO Sysfs

To use pins other than the already exported ones directly from user space through sysfs they first have to be exported as GPIOs.

To export a particular pin as GPIO for user control proceed as follows (GPIO 189 is taken as an example):

Note: The relationship between SOC GPIO names and the 'magic' numbers used here can be found on this page.

Note: E.g. the Tegra SoC defines GPIOs with an alphanumeric term, e.g. X5 (GPIO 189) but the Linux kernel uses a numeric-only representation in its GPIO subsystem and in the sysfs interface to the GPIO functionality.

$ echo 189 > /sys/class/gpio/export

To change that GPIO pins direction to in/out:

$ echo "in" > /sys/class/gpio/gpio189/direction

or

$ echo "out" > /sys/class/gpio/gpio189/direction

To check the value (in case its direction is input):

$ cat /sys/class/gpio/gpio189/value

To change its value (in case its direction is output):

$ echo 1 > /sys/class/gpio/gpio189/value

or

$ echo 0 > /sys/class/gpio/gpio189/value

To directly force a GPIO to output and set its initial value (e.g. glitch free operation):

$ echo high > /sys/class/gpio/gpio189/direction

or

$ echo low > /sys/class/gpio/gpio189/direction

To configure a GPIO as an interrupt source:

Note: If a GPIO is configured as an input, one can configure the GPIO as an interrupt source. Configure GPIO if the interrupt occurs when the GPIO signal has a rising edge, a falling edge, or interrupts on both rising and falling edges.

$ echo "rising" > /sys/class/gpio/gpio189/edge

Possible values

  • rising: Trigger on rising edge
  • falling: Trigger on falling edge
  • both: Trigger on both edges
  • none: Disable interrupt on both edges

To un-export aka revert the exporting of a GPIO pin:

$ echo 189 > /sys/class/gpio/unexport

Note: GPIOs which are already used in the drivers can not be controlled from sysfs, unless a driver explicitly exported that particular pins GPIO.

More information concerning the Linux' GPIO subsystem can be found in the following kernel documentation file:

http://git.toradex.com/cgit/linux-toradex.git/tree/Documentation/gpio.txt

GPIO Power Management Keys

Linux systems use key events to initiate a clean shutdown or suspend-to-memory sequence. On a typical PC, pressing the power button generates a key event which will lead to a shutdown of the system. For an embedded system, a GPIO with a key code assigned can be used to trigger key events. When the key is pressed (GPIO triggered), the system will initiate the sequence.

The systemd service systemd-logind is the user-space program listening to key events (if they are tagged with the string "power-switch", see below). Four key codes are supported:

  • KEY_POWER = initiate shutdown
  • KEY_POWER2 = initiate shutdown
  • KEY_SLEEP = suspend-to-ram, commonly known as "suspend"
  • KEY_SUSPEND = suspend-to-disk, commonly known as "hibernate"

There are two steps required:

  1. Declare a GPIO as input device and assign a key code using the GPIO keyboard driver
  2. Use a udev rule to tag the GPIO input device

GPIO Keyboard Driver

For device tree enabled kernels, a node as follows can be used in the carrier board device tree file:

gpio-keys {
    compatible = "gpio-keys";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_gpiokeys>;
    power {
            label = "Power-Key";
            gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
            linux,code = <KEY_POWER>;
            debounce-interval = <10>;
    };
};

For details how to customise the device tree refer to the Device Tree Customization article.

For Apalis T30, the predefined macro POWER_GPIO in the board file can be enabled to enable the power key code (see this commit). For the Colibri T20/T30 boards a similar approach can be adopted.

For Colibri T30, the example below enables SODIMM Pin 162 as a suspend pin

diff --git a/arch/arm/mach-tegra/board-colibri_t30.c b/arch/arm/mach-tegra/board-colibri_t30.c
index 7265d8d..2c4079e 100644
--- a/arch/arm/mach-tegra/board-colibri_t30.c
+++ b/arch/arm/mach-tegra/board-colibri_t30.c
@@ -394,7 +394,7 @@ static struct gpio colibri_t30_gpios[] = {
 // {TEGRA_GPIO_PN3,    GPIOF_IN,   "SODIMM pin 180"},
 // {TEGRA_GPIO_PN4,    GPIOF_IN,   "SODIMM pin 160"},
 // {TEGRA_GPIO_PN5,    GPIOF_IN,   "SODIMM pin 158"},
-   {TEGRA_GPIO_PN6,    GPIOF_IN,   "SODIMM pin 162"},
+// {TEGRA_GPIO_PN6,    GPIOF_IN,   "SODIMM pin 162"},
 //conflicts with ADDRESS13
 // {TEGRA_GPIO_PP4,    GPIOF_IN,   "SODIMM pin 120"},
 //conflicts with ADDRESS14
@@ -668,6 +668,7 @@ static struct gpio_keys_button colibri_t30_keys[] = {
    GPIO_KEY(KEY_POWER, PV1, 0, 1),     /* SODIMM pin 45,
                           Iris X16-20 */
    GPIO_KEY(KEY_MENU, PK6, 1, 0),      /* SODIMM pin 135 */
+   GPIO_KEY(KEY_SLEEP, PN6, 0, 0),     /* SODIMM pin 162 */
 };
 
 static struct gpio_keys_platform_data colibri_t30_keys_platform_data = {
-- 
2.6.3

Tag the GPIO Input Device

Use a udev rule to add the power-switch tag to the GPIO key event source. Store the file in a udev rules directory, e.g. /etc/udev/rules.d/power-key.rules

ACTION=="remove", GOTO="power_switch_end"

SUBSYSTEM=="input", KERNEL=="event*", ENV{ID_PATH}=="platform-gpio-keys*", ATTRS{keys}=="*", TAG+="power-switch" 
                                               
LABEL="power_switch_end"

With that, all key codes get tagged as power-switch events, and systemd will interpret the relevant key codes. The exact behaviour can be fine tuned through HandlePowerKey/HandleSuspendKey and HandleHibernateKey in /etc/systemd/logind.conf.

GPIO Power-Off

To power off a system completely after shutdown, often a GPIO is needed to switch off the system. Newer Kernel provide a specific GPIO power-off driver to achieve this.

Our Colibri and Apalis Evaluation Carrier Boards have a push button power on/off controller (LTC2954) which has a GPIO input FORCE_OFF# (X4-5 on Colibri or X61-5 on Apalis). This signal makes sure that the DC-DC converter on the carrier board are switched-off completely, as if the user pressed the on/off button. After connecting these signal to a GPIO, the GPIO power-off driver need to be enabled. On device-tree based kernels (e.g. Colibri/Apalis iMX6 and Colibri VF50/VF61), the driver CONFIG_POWER_RESET_GPIO need to be enabled (up to v2.3Beta5 this is not the case by default). Furthermore a new node need to be added which specifies the GPIO to switch power off. This example uses SO-DIMM 135 (EXT_IO_0) as power-off GPIO for Colibri VF50/VF61 modules:

gpio-poweroff {
    compatible = "gpio-poweroff";
    gpios = <&gpio2 25 GPIO_ACTIVE_LOW>;
};

The poweroff command need to be used to power-off the system completely ("halt" does not work):

# poweroff

For Apalis T30, the predefined macro FORCE_OFF_GPIO in the board file can be enabled (see this commit). For the Colibri T20/T30 boards a similar approach can be adopted.

For i.MX6 based modules CONFIG_POWER_RESET_GPIO must be set in the kernel configuration. Additionally for the 3.10.17 kernel version you will have to at least cherry-pick this commit or use the toradex_imx_3.10.17_1.0.0_ga-next branch.

GPIO LED

The GPIO LED driver allows to use a GPIO to control a LED. Using the Kernels LED driver framework has the advantage that triggers can be specified, which allow to use an LED as a visual activity signal for various system activities.

leds {
    compatible = "gpio-leds";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_gpio_leds>;

    led0: user1 {
        label = "user1";
        gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>; /* SODIMM 103 */
        default-state = "off";
        linux,default-trigger = "mmc0";
    };
};
...
pinctrl_gpio_leds: gpioleds {
    fsl,pins = <
        VF610_PAD_PTC3__GPIO_48         0x2180
    >;
};

You can also get a list of valid triggers (and configure the active trigger) through the sysfs file at /sys/class/leds/user1/trigger.

GPIO U-Boot

One can also access GPIOs from U-Boot. This allows to implement functionality such as “Press button X and turn device ON to upgrade firmware” using U-Boot scripts.

The GPIO driver can be used from within the U-Boot source code. Additionally the GPIO driver has a corresponding gpio command line interface that can be used to set and get GPIO values. Note that for the command line interface to work the corresponding pin must be muxed to its GPIO functionality in the U-Boot code.

On a Colibri VF accesses from code allow to set a GPIO around 40ms, access from the command line interface in 'bootcmd' 70ms after power up.

Note: The relationship between SOC GPIO names and the 'magic' numbers used here can be found on this page.

Command Line Interface

# gpio help
gpio - query and control gpio pins

Usage:
gpio  
    - input/set/clear/toggle the specified pin
gpio status [-a] [ | ]  - show [all/claimed] GPIOs

To set the GPIO:

# gpio set [gpio-number]

To clear the GPIO

# gpio clear [gpio-number]

To toggle the GPIO

# gpio toggle [gpio-number]

To read the state of GPIO:

# gpio input [gpio-number]
Examples

To clear GPIO #22 (Backlight PWM configured as GPIO on a Colibri VF) do:

# gpio out 22

To read GPIO #10 (UART A, DTR on a Colibri VF) do:

Colibri VFxx # gpio input 10
gpio: pin 10 (gpio 10) value is 0

To read GPIO #10 (UART A, DTR on a Colibri VF) and react on the read value do:

Colibri VFxx # if gpio input 10 ; then echo "commands for 0" ; else echo "commands for 1" ; fi
gpio: pin 10 (gpio 10) value is 0
commands for 0

From Source Code

To access a GPIO earlier than what would be possible from the U-Boot command line or to include it in a algorithm written in source code use the GPIO API. In most cases this code would live in the board file (e.g. board/toradex/colibri_vf/colibri_vf.c).

The GPIO's need to be configured only after the GPIO driver is loaded, if a GPIO gets configured before the driver has been loaded, the GPIO functions will have no effect. The 'board_init' function is called just after GPIO initialization and hence is a appropriate place to configure custom GPIO's.

e.g. To set GPIO_10 during boot from board file:

 diff --git i/board/toradex/colibri_vf/colibri_vf.c w/board/toradex/colibri_vf/colibri_vf.c
 index 3272733..ca30af8 100644
 --- i/board/toradex/colibri_vf/colibri_vf.c
 +++ w/board/toradex/colibri_vf/colibri_vf.c
 @@ -478,6 +483,11 @@ int board_init(void)
          */
  
         setbits_le32(&scsc->sosc_ctr, SCSC_SOSC_CTR_SOSC_EN);
 +#ifdef CONFIG_VYBRID_GPIO
 +       gpio_request(10, "SODIMM_PIN_23");
 +       gpio_direction_output(10, 1);
 +#endif

GPIO Debugging

All "free" Pins are configured as GPIOs by default and are already exported from within the board specific platform configuration to be used from user space through the sysfs interface.

To know what GPIOs are currently exported from the platform configuration resp. requested from drivers proceed as follows:

$ cat /sys/kernel/debug/gpio

Apalis T30

root@apalis-t30:~# cat /sys/kernel/debug/gpio 
GPIOs 0-255, tegra-gpio:
 gpio-6   (Just for testing    ) in  lo
 gpio-26  (THERMD_ALERT_N      ) in  hi
 gpio-68  (RESET_MOCI_N        ) out hi
 gpio-111 (HDMI1_HPD           ) in  lo
 gpio-128 (GPIO6 X1-11         ) in  lo
 gpio-129 (GPIO8 X1-15, FAN    ) in  lo
 gpio-146 (GPIO1 X1-1          ) in  lo
 gpio-147 (GPIO2 X1-3          ) in  lo
 gpio-148 (GPIO3 X1-5          ) in  lo
 gpio-149 (GPIO4 X1-7          ) in  lo
 gpio-150 (GPIO5 X1-9          ) in  lo
 gpio-151 (PEX_PERST_N         ) out hi
 gpio-168 (TOUCH_PEN_INT       ) in  hi
 gpio-169 (KEY_POWER           ) in  hi
 gpio-170 (BKL1_ON             ) out hi
 gpio-171 (sdhci_cd            ) in  hi
 gpio-216 (LVDS: Single/Dual Ch) out lo
 gpio-219 (LVDS: 18/24 Bit Mode) out hi
 gpio-220 (LVDS: Output Enable ) out hi
 gpio-221 (LVDS: Power Down    ) out hi
 gpio-222 (LVDS: Clock Polarity) out hi
 gpio-223 (LVDS: Colour Mapping) out hi
 gpio-225 (LVDS: Swing Mode    ) out hi
 gpio-226 (LVDS: DDRclk Disable) out hi
 gpio-229 (sdhci_cd            ) in  hi
 gpio-232 (SATA1_ACT_N         ) out hi
 gpio-233 (usb_host_vbus       ) out hi

GPIOs 256-264, i2c/4-002d, tps6591x, can sleep:
 gpio-262 (fixed_reg_en_hdmi   ) out hi

Apalis TK1

root@apalis-tk1:~# cat /sys/kernel/debug/gpio GPIOs 0-255, platform/6000d000.gpio, tegra-gpio: gpio-63 (+V1.05_AVDD_HDMI_PLL) out lo gpio-70 (temp_alert ) in hi gpio-108 (VCC_USBO1 ) out lo gpio-109 (VCC_USBH(2A|2C|2D|3|) out hi gpio-111 (hdmi_hpd ) in hi gpio-146 (LAN_RESET_N ) out hi gpio-164 (RESET_MOCI_N ) out hi gpio-170 (sdhci_cd ) in hi gpio-171 (sdhci_cd ) in hi gpio-221 (BKL1_ON ) out hi gpio-233 (PEX_PERST_N ) out hi gpio-235 (WAKE1_MICO ) in hi

GPIOs 1016-1023, platform/as3722-pinctrl, as3722-gpio, can sleep: gpio-1018 (+V3.3 ) out hi

Apalis iMX6

root@apalis-imx6:~# cat /sys/kernel/debug/gpio
GPIOs 0-31, platform/209c000.gpio, 209c000.gpio:
 gpio-0   (usb_host_vbus       ) out lo
 gpio-2   (PCIe reset          ) out lo
 gpio-4   (Wake-Up             ) in  hi
 gpio-6   (sysfs               ) in  lo
 gpio-25  (phy-reset           ) out lo
 gpio-28  (PCIe EP reset       ) out lo

GPIOs 32-63, platform/20a0000.gpio, 20a0000.gpio:
 gpio-36  (sysfs               ) in  lo
 gpio-37  (sysfs               ) in  lo
 gpio-38  (sysfs               ) in  lo
 gpio-39  (sysfs               ) in  lo
 gpio-58  (spi_imx             ) out lo
 gpio-62  (scl                 ) in  hi

GPIOs 64-95, platform/20a4000.gpio, 20a4000.gpio:
 gpio-80  (sda                 ) in  hi
 gpio-86  (usb_otg_vbus        ) out lo
 gpio-92  (usb_host_vbus_hub   ) out lo

GPIOs 96-127, platform/20a8000.gpio, 20a8000.gpio:
 gpio-116 (cd                  ) in  hi

GPIOs 128-159, platform/20ac000.gpio, 20ac000.gpio:
 gpio-153 (spi_imx             ) out lo

GPIOs 160-191, platform/20b0000.gpio, 20b0000.gpio:
 gpio-174 (cd                  ) in  hi

GPIOs 192-223, platform/20b4000.gpio, 20b4000.gpio:

Colibri T20

root@colibri_t20:~# cat /sys/kernel/debug/gpio
GPIOs 0-223, tegra-gpio:
 gpio-0   (SODIMM pin 73       ) in  hi
 gpio-2   (SODIMM pin 186      ) in  lo
 gpio-3   (SODIMM pin 184      ) in  lo
 gpio-10  (SODIMM pin 154      ) out hi
 gpio-13  (sysfs               ) out hi
 gpio-14  (SODIMM pin 55       ) in  hi
 gpio-15  (SODIMM pin 63       ) in  hi
 gpio-22  (sysfs               ) out hi
 gpio-23  (sdhci4_cd           ) in  hi irq-215 edge-both
 gpio-29  (SODI-98, Iris X16-13) in  lo
 gpio-67  (SODIMM pin 130      ) in  hi
 gpio-68  (SODIMM pin 87       ) in  hi
 gpio-70  (SODIMM pin 132      ) in  hi
 gpio-80  (SODIMM pin 150      ) in  lo
 gpio-81  (SODIMM pin 152      ) in  lo
 gpio-84  (SODIMM pin 106      ) in  lo
 gpio-88  (SOD-101, Iris X16-16) in  lo
 gpio-89  (SOD-103, Iris X16-15) in  lo
 gpio-90  (SODI-79, Iris X16-19) in  lo
 gpio-91  (SODI-97, Iris X16-17) in  lo
 gpio-94  (SODI-85, Iris X16-18) in  lo
 gpio-104 (SODIMM pin 174      ) in  lo
 gpio-105 (SODIMM pin 176      ) in  lo
 gpio-106 (SODIMM pin 178      ) in  lo
 gpio-107 (SODIMM pin 180      ) in  lo
 gpio-108 (SODIMM pin 160      ) in  lo
 gpio-109 (SODIMM pin 158      ) in  lo
 gpio-110 (SODIMM pin 162      ) in  lo
 gpio-111 (sysfs               ) in  hi irq-303 edge-both
 gpio-124 (SODIMM pin 120      ) in  lo
 gpio-125 (SODIMM pin 122      ) in  lo
 gpio-126 (SODIMM pin 124      ) in  lo
 gpio-127 (SODIMM pin 188      ) in  lo
 gpio-144 (nand_wp             ) out hi
 gpio-154 (SODIMM pin 69       ) in  lo
 gpio-155 (SODIMM pin 77       ) in  lo
 gpio-156 (BL_ON               ) out hi
 gpio-166 (SODIMM pin 118      ) in  lo
 gpio-168 (WOLFSON_RESET       ) out hi
 gpio-169 (ulpi_phy_reset_b    ) out hi
 gpio-171 (SODI-45, Iris X16-20) in  lo
 gpio-172 (ethernet_reset      ) out hi
 gpio-176 (sysfs               ) out hi
 gpio-178 (VBUS_BUS            ) out lo
 gpio-184 (SODIMM pin 142      ) in  lo
 gpio-185 (SODIMM pin 140      ) in  lo
 gpio-186 (SODIMM pin 138      ) in  lo
 gpio-187 (SODIMM pin 136      ) in  lo
 gpio-188 (SODIMM pin 134      ) in  lo
 gpio-190 (102, I X13 ForceOFF#) in  hi
 gpio-191 (104, I X14 ForceOFF#) in  hi
 gpio-202 (SODIMM pin 156      ) in  lo
 gpio-204 (SODIMM pin 164      ) in  lo
 gpio-212 (SODIMM pin 166      ) in  lo
 gpio-213 (SODIMM pin 168      ) in  lo
 gpio-214 (SODIMM pin 170      ) in  lo
 gpio-215 (SODIMM pin 172      ) in  lo
 gpio-217 (ethernet_vbus       ) out hi
 gpio-218 (SOD-133, Iris X16-14) in  lo
 gpio-219 (SODIMM pin 127      ) in  lo
 gpio-220 (SODIMM pin 22       ) in  lo

GPIOs 224-227, i2c/4-0034, tps6586x, can sleep:

Colibri T30

root@colibri-t30:~# cat /sys/kernel/debug/gpio
GPIOs 0-255, tegra-gpio:
 gpio-10  (SODIMM pin 154      ) in  lo
 gpio-17  (SODIMM pin 81       ) in  lo
 gpio-23  (sdhci_cd            ) in  hi
 gpio-26  (THERMD_ALERT        ) in  hi
 gpio-67  (SODIMM pin 130      ) in  lo
 gpio-70  (SODIMM pin 132      ) in  lo
 gpio-85  (USBC_DET            ) in  hi
 gpio-86  (KEY_MENU            ) in  lo
 gpio-110 (SODIMM pin 162      ) in  lo
 gpio-111 (hdmi_hpd            ) in  lo
 gpio-144 (SODIMM pin 73       ) in  hi
 gpio-153 (EN_MIC_GND          ) out hi
 gpio-157 (KEY_BACK            ) in  hi
 gpio-158 (KEY_HOME            ) in  hi
 gpio-168 (TOUCH_PEN_INT       ) in  hi
 gpio-169 (KEY_POWER           ) in  lo
 gpio-170 (BL_ON               ) out hi
 gpio-171 (SODI-85, Iris X16-18) in  hi
 gpio-178 (usb_host_vbus       ) out lo
 gpio-181 (SODIMM pin 75       ) in  lo
 gpio-188 (SODIMM pin 134      ) in  lo
 gpio-190 (102, I X13 ForceOFF#) in  lo
 gpio-191 (104, I X14 ForceOFF#) in  lo
 gpio-220 (SODIMM pin 166      ) in  lo
 gpio-221 (SODIMM pin 168      ) in  lo
 gpio-222 (SODIMM pin 170      ) in  lo
 gpio-223 (SODIMM pin 172      ) in  lo
 gpio-226 (KEY_FIND            ) in  hi
 gpio-230 (KEY_VOLUMEDOWN      ) in  hi
 gpio-231 (SODIMM pin 94       ) in  hi
 gpio-232 (LAN_RESET           ) out hi
 gpio-234 (LAN_V_BUS           ) out hi
 gpio-237 (SODIMM pin 69       ) in  hi
 gpio-238 (SODIMM pin 65       ) in  hi
 gpio-239 (KEY_VOLUMEUP        ) in  hi

GPIOs 256-264, i2c/4-002d, tps6591x, can sleep:
 gpio-262 (fixed_reg_en_hdmi   ) out lo

Colibri VF50

root@colibri-vf:~# cat /sys/kernel/debug/gpio 
GPIOs 0-31, platform/40049000.gpio, vf610-gpio:
 gpio-4   (ym                  ) out hi    
 gpio-8   (pen-detect          ) in  hi IRQ
 gpio-12  (yp                  ) out hi    
 gpio-13  (xp                  ) out hi    

GPIOs 32-63, platform/4004a000.gpio, vf610-gpio:
 gpio-41  (Wake-Up             ) in  hi IRQ
 gpio-42  (cd                  ) in  lo    
 gpio-45  (backlight           ) out hi    

GPIOs 64-95, platform/4004b000.gpio, vf610-gpio:
 gpio-83  (usbh_vbus           ) out lo    
 gpio-93  (xm                  ) out lo    

GPIOs 96-127, platform/4004c000.gpio, vf610-gpio:
 gpio-102 (id                  ) in  hi IRQ

GPIOs 128-159, platform/4004d000.gpio, vf610-gpio:

Colibri VF61

root@colibri-vf:~# cat /sys/kernel/debug/gpio 
GPIOs 0-31, platform/40049000.gpio, vf610-gpio:
 gpio-8   (AC97 link sdata     ) out lo    
 gpio-9   (AC97 link sync      ) out lo    
 gpio-13  (AC97 link reset     ) out hi    

GPIOs 32-63, platform/4004a000.gpio, vf610-gpio:
 gpio-41  (Wake-Up             ) in  hi IRQ
 gpio-42  (cd                  ) in  lo    
 gpio-45  (backlight           ) out hi    

GPIOs 64-95, platform/4004b000.gpio, vf610-gpio:
 gpio-83  (usbh_vbus           ) out lo    

GPIOs 96-127, platform/4004c000.gpio, vf610-gpio:
 gpio-102 (id                  ) in  hi IRQ

GPIOs 128-159, platform/4004d000.gpio, vf610-gpio: