Kernel Space GPIO Manipulation
For the FMQL45T900 platform based on the Zynq-7000 architecture, controlling pins from the kernel space requires determining the correct GPIO index. When utilizing EMIO5 exported from Vivado, the corresponding system GPIO number calculates to 431. The device tree mapping for this pin appears as <&portc 5 0x01>.
Module Compilation Setup
Adjust the kernel source directory in the Makefile according to your build environment before compiling the kernel object.
obj-m += zynq_pin_ctrl.o
KDIR ?= /home/FMQL-Linux-SDK-Prj/linux-4.14.55-fmsh
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
Standard Kernel GPIO API
The Linux kernel provides a standard set of functions for pin manipulation:
| API Function | Parameters | Description |
|---|---|---|
| gpio_is_valid | pin number | Checks if the GPIO index is valid |
| gpio_request | pin number, label | Allocates the GPIO for exclusive use |
| gpio_direction_input | pin number | Sets the pin direction to input |
| gpio_get_value | pin number | Reads the current logic level |
| gpio_direction_output | pin number, default value | Sets the pin direction to output |
| gpio_set_value | pin number, logic level | Drives the pin to the specified level |
Driver Implementation Example
The following snippet demonstrates allocating the pin, configuring it as an output, driving it high, reconfiguring it as an input, and reading its state:
/*
* Target: FMQL45T900
* Test Pin: EMIO5
* DT entry: <&portc 5 0x01>
*/
#define MODULE_TAG "zynq_gpio_dev"
#define PIN_ID 431 // EMIO5
int setup_pin(int pin) {
int ret_val, pin_state;
if (!gpio_is_valid(pin)) {
pr_err("Invalid GPIO specified\n");
return -ENODEV;
}
ret_val = gpio_request(pin, "emio_test_pin");
if (ret_val) {
pr_err("GPIO allocation failed\n");
return ret_val;
}
// Configure as output initially
ret_val = gpio_direction_output(pin, 0);
if (ret_val) {
pr_err("Failed to configure as output\n");
gpio_free(pin);
return ret_val;
}
gpio_set_value(pin, 1); // Drive high
pr_info("%s: Pin driven HIGH\n", MODULE_TAG);
// Switch to input and read
ret_val = gpio_direction_input(pin);
if (ret_val) {
pr_err("Failed to reconfigure as input\n");
gpio_free(pin);
return ret_val;
}
pin_state = gpio_get_value(pin);
pr_info("%s: Pin state read as %d\n", MODULE_TAG, pin_state);
gpio_free(pin);
return 0;
}
Module Deployment
Load the compiled module into the running kernel:
insmod zynq_pin_ctrl.ko
Remove the module from the kernel:
rmmod zynq_pin_ctrl