I'm using a Raspberry Pi 4 with standard 32 bit Raspbian. I'm trying to write a driver in c that writes AT commands to some GPIO pins and reads the response from other pins. For that I want to use the open() and write() commands from Linux onto a character device f.e. /dev/gpio or similar.

However these devices do not exist, all I could find so far was /dev/gpiochip0 and /dev/gpiochip1 but no gpiohip2 or beyond. I've looked for some source codes which seems to suggest that a character device for each pin should exist (or did exist in the past...), but no matter where (/dev/, /sys/class/gpio/, /sys/bus/gpio/devices/) I look there are a maximum of two pins represented as char devices.

One of the codes that I found was: https://elinux.org/RPi_GPIO_Code_Samples

snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
fd = open(path, O_WRONLY);

where the path on my Raspbian only contains a link to "gpiochip0" and "gpiochip504" folders, neither of which contain a file called direction.

I'm guessing that either I have to activate something to make the char devices appear or use a different access method for each pin. How can I write or read from a specific GPIO pin in from a kernel-module?


3 Answers 3


I think you have misinterpreted what you are seeing.

On the Pi /dev/gpiochip0 is the main GPIO block of 54 GPIO and corresponds to Broadcom GPIO 0 to 53. This includes all the GPIO you can access from the extension header.

Pi400 /dev/gpiochip0

lines=54 name=gpiochip0 label=pinctrl-bcm2835
offset=0 flags=0 name=ID_SDA user=
offset=1 flags=0 name=ID_SCL user=
offset=2 flags=0 name=SDA1 user=
offset=3 flags=0 name=SCL1 user=
offset=4 flags=0 name=GPIO_GCLK user=
offset=5 flags=0 name=GPIO5 user=
offset=6 flags=0 name=GPIO6 user=
offset=7 flags=7 name=SPI_CE1_N user=spi0 CS1
offset=8 flags=7 name=SPI_CE0_N user=spi0 CS0
offset=9 flags=0 name=SPI_MISO user=
offset=10 flags=0 name=SPI_MOSI user=
offset=11 flags=0 name=SPI_SCLK user=
offset=12 flags=0 name=GPIO12 user=
offset=13 flags=0 name=GPIO13 user=
offset=14 flags=0 name=TXD1 user=
offset=15 flags=0 name=RXD1 user=
offset=16 flags=0 name=GPIO16 user=
offset=17 flags=3 name=GPIO17 user=gpio-fan@0
offset=18 flags=0 name=GPIO18 user=
offset=19 flags=0 name=GPIO19 user=
offset=20 flags=0 name=GPIO20 user=
offset=21 flags=0 name=GPIO21 user=
offset=22 flags=0 name=GPIO22 user=
offset=23 flags=0 name=GPIO23 user=
offset=24 flags=0 name=GPIO24 user=
offset=25 flags=0 name=GPIO25 user=
offset=26 flags=0 name=GPIO26 user=
offset=27 flags=0 name=GPIO27 user=
offset=28 flags=0 name=RGMII_MDIO user=
offset=29 flags=0 name=RGMIO_MDC user=
offset=30 flags=0 name=CTS0 user=
offset=31 flags=0 name=RTS0 user=
offset=32 flags=0 name=TXD0 user=
offset=33 flags=0 name=RXD0 user=
offset=34 flags=0 name=SD1_CLK user=
offset=35 flags=0 name=SD1_CMD user=
offset=36 flags=0 name=SD1_DATA0 user=
offset=37 flags=0 name=SD1_DATA1 user=
offset=38 flags=0 name=SD1_DATA2 user=
offset=39 flags=0 name=SD1_DATA3 user=
offset=40 flags=0 name=PWM0_MISO user=
offset=41 flags=0 name=PWM1_MOSI user=
offset=42 flags=3 name=STATUS_LED_G_CLK user=led0
offset=43 flags=0 name=SPIFLASH_CE_N user=
offset=44 flags=0 name=SDA0 user=
offset=45 flags=0 name=SCL0 user=
offset=46 flags=0 name=RGMII_RXCLK user=
offset=47 flags=0 name=RGMII_RXCTL user=
offset=48 flags=0 name=RGMII_RXD0 user=
offset=49 flags=0 name=RGMII_RXD1 user=
offset=50 flags=0 name=RGMII_RXD2 user=
offset=51 flags=0 name=RGMII_RXD3 user=
offset=52 flags=0 name=RGMII_TXCLK user=
offset=53 flags=0 name=RGMII_TXCTL user=

/dev/gpiochip1 is a secondary block of GPIO.

Pi400 /dev/gpiochip1

lines=8 name=gpiochip1 label=raspberrypi-exp-gpio

offset=0 flags=2 name=BT_ON user=
offset=1 flags=2 name=WL_ON user=
offset=2 flags=7 name=PWR_LED_OFF user=led1
offset=3 flags=2 name=GLOBAL_RESET user=
offset=4 flags=3 name=VDD_SD_IO_SEL user=vdd-sd-io
offset=5 flags=3 name=CAM_GPIO user=power_ctrl
offset=6 flags=3 name=SD_PWR_ON user=sd_vcc_reg
offset=7 flags=0 name=SD_OC_N user=

After searching endlessly to control a GPIO pin on Raspberry Pi 4 (cm4 module) from a kernel driver module (with kernel version: 5.19.17), I came up with the following simple solution directly accessing gpiolib:-

static int is_right_chip(struct gpio_chip *chip, void *data)
    if (strcmp(data, chip->label) == 0)
            return 1;
    return 0;

void waggleGPIO(void) 
    // point to gpiochip0.. use chip name given by userspace gpio utility: gpiodetect (in this example: pinctrl-bcm2711)
    struct gpio_chip *chip = gpiochip_find("pinctrl-bcm2711", is_right_chip);
    if (!chip) {
        printk("FAIL to file pinctrl-bcm2711 gpiochip0!\n");    
    else {
        printk("GOOD..found gpiochip0\n");
        // using userspace utility: gpioinfo, decide which line you want to read or write.. in this example gpio24 (gpiochip0 index 24)
        chip->direction_output(chip, 24, 0);  //set direction to output and drive pin low... this calls bcm2835_gpio_direction_output()
        chip->set(chip, 24, 1);  // this drives gpio24 to a high level
        chip->set(chip, 24, 0);  // this drives gpio24 to a low level

Similar gpiolib functions can be used to read the state of the GPIO line using:-

int gpio24Value = chip->direction_input(chip, 24);
gpio24Value = chip->get(chip, 24);

Note that this example does poke around with the internals of gpiolib.

I hope this helps someone!

tags: drive GPIO in Linux kernel


The interface described here no longer works on Raspberry Pi OS bookworm.

echo 20 > /sys/class/gpio/export 
-bash: echo: write error: Invalid argument
  • how does that answer the question?
    – jsotola
    Apr 9 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.