This message will disappear after all relevant tasks have been resolved.
Semantic MediaWiki
There are 1 incomplete or pending task to finish installation of Semantic MediaWiki. An administrator or user with sufficient rights can complete it. This should be done before adding new data to avoid inconsistencies.1. Purpose[edit source]
This article gives an example of a driver that controls GPIOs from kernel space.
Sample source files are provided as examples: kernel module (driver), device tree and Makefile.
This example is available for STM32MP15_Evaluation_boards or STM32MP15_Discovery_kits
2. Code[edit source]
2.1. Objective[edit source]
Sample gpiolib usage code that makes an LED blink for 20 seconds.
2.2. Device tree[edit source]
dummy_device { compatible = "st,dummy"; status = "okay"; greenled-gpios = <&gpioa 14 0>; };
See GPIO_device_tree_configuration for more details of GPIO use in a device tree.
2.3. Kernel module code[edit source]
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
struct gpio_desc *red, *green;
static int gpio_init_probe(struct platform_device *pdev)
{
int i = 0;
printk("GPIO example init\n");
/* "greenled" label is matching the device tree declaration. OUT_LOW is the value at init */
green = devm_gpiod_get(&pdev->dev, "greenled", GPIOD_OUT_LOW);
/* blink of the green led */
while (i < 10)
{
ssleep(1);
gpiod_set_value(green, 1);
ssleep(1);
gpiod_set_value(green, 0);
i++;
}
return(0);
}
static int gpio_exit_remove(struct platform_device *pdev)
{
printk("GPIO example exit\n");
return(0);
}
/* this structure does the matching with the device tree */
/* if it does not match the compatible field of DT, nothing happens */
static struct of_device_id dummy_match[] = {
{.compatible = "st,dummy"},
{/* end node */}
};
static struct platform_driver dummy_driver = {
.probe = gpio_init_probe,
.remove = gpio_exit_remove,
.driver = {
.name = "dummy_driver",
.owner = THIS_MODULE,
.of_match_table = dummy_match,
}
};
module_platform_driver(dummy_driver);
MODULE_AUTHOR("Bernard Puel");
MODULE_DESCRIPTION("Gpio example");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dummy_driver");
2.4. Kernel module build[edit source]
See Adding_external_out-of-tree_Linux_kernel_modules for further information on module compilation.
2.5. Kernel module use[edit source]
scp dummy_driver.ko root@<board ip address>:/lib/modules/
- Update dependency descriptions for loadable kernel modules, and synchronize the data on disk with memory
/sbin/depmod -a sync
- Insert the kernel module example into the Linux kernel
modprobe dummy_driver [18167.821725] dummy_driver: GPIO example init
3. A simple example which initializes a GPIO with a pull-up configuration[edit source]
3.1. Adding nodes in the Device Tree[edit source]
- Copy these two following nodes into the board dts file:
workspace/sources/linux-stm32mp/arm/boot/dts/stm32mp157-dk2.dts
/ {
ledpa14 {
compatible = "st,dummypu";
pinctrl-names = "default";
pinctrl-0 = <&keyleds_pins_a>;
status = "okay";
};
}
&pinctrl {
keyleds_pins_a: keyleds_pins_a-0 {
pins {
pinmux = <STM32_PINMUX('A', 14, GPIO)>;
bias-pull-up;
drive-push-pull;
slew-rate = <0>;
};
};
};
- Create a second dummy driver (dummy_driver_pu.c) since PA14 toggling is already used by "dummy_driver"
dummy_driver_pu.c
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
static int gpio_init_probe(struct platform_device *pdev)
{
printk("GPIO setting pu init\n");
return(0);
}
static int gpio_exit_remove(struct platform_device *pdev)
{
printk("GPIO setting pu exit\n");
return(0);
}
/* this structure does the matching with the device tree */
/* if it does not match the compatible field of DT, nothing happens */
static struct of_device_id dummy_match[] = {
{.compatible = "st,dummypu"},
{/* end node */}
};
static struct platform_driver dummy_driver_pu = {
.probe = gpio_init_probe,
.remove = gpio_exit_remove,
.driver = {
.name = "dummy_driver_pu",
.owner = THIS_MODULE,
.of_match_table = dummy_match,
}
};
module_platform_driver(dummy_driver_pu);
MODULE_AUTHOR("OK");
MODULE_DESCRIPTION("Gpio pu");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dummy_driver_pu");
- Then cross-compile the Kernel and push it on the board as in STM32MP1_Developer_Package#Modifying_the_Linux_kernel_device_tree
3.2. Interacting on the board[edit source]
- Read the GPIO pin PA14 default setting configuration
root@stm32mp1:reboot
root@stm32mp1:~# cat /sys/kernel/debug/pinctrl/soc\:pin-controller@50002000/pinconf-pins | grep PA14
pin 14 (PA14): input - high - floating
- Describe the use of pins
root@stm32mp1:~# gpioinfo gpiochip0 | grep 14
line 14: unnamed unused input active-high
- Enable the green LED on the board (control of GPIO in userspace, gpio switched to output pushpull)
root@stm32mp1:~# gpioset gpiochip0 14=0
root@stm32mp1:~# cat /sys/kernel/debug/pinctrl/soc\:pin-controller@50002000/pinconf-pins | grep PA14
pin 14 (PA14): output - low - push pull - floating - low speed
root@stm32mp1:~# gpioinfo gpiochip0 | grep 14
line 14: unnamed unused output active-high
- Now let's probe the dummy driver to enable the pullup on PA14 :
root@stm32mp1:~# modprobe dummy_driver_pu
[ 1598.403140] GPIO setting pu init
root@stm32mp1:~# cat /sys/kernel/debug/pinctrl/soc\:pin-controller@50002000/pinconf-pins | grep PA14
pin 14 (PA14): input - high - pull up
root@stm32mp1:~# gpioinfo gpiochip0 | grep 14
line 14: unnamed unused output active-high
- Enable green led again (control of GPIO in userspace, check that the pullup config is still there)
root@stm32mp1:~# gpioset gpiochip0 14=0
root@stm32mp1:~# cat /sys/kernel/debug/pinctrl/soc\:pin-controller@50002000/pinconf-pins | grep PA14
pin 14 (PA14): output - low - push pull - pull up - low speed