驱动、bootloader、文件系统

内核4.8后与4.8之前的gpio差异

内核4.8后与4.8之前的gpio差异的封面

在 Linux 内核中,有专门用于控制 GPIO(General - Purpose Input/Output,通用输入输出)输出的函数。

4.8 之前的内核

在较旧的 Linux 内核版本中,使用的是传统的 GPIO 接口。相关函数主要定义在 <linux/gpio.h> 头文件中。

1、请求GPIO

在使用 GPIO 之前,需要先请求该 GPIO 资源,以确保不会与其他驱动冲突。

#include <linux/gpio.h>

int gpio_request(unsigned gpio, const char *label);

2、设置GPIO方向输出

int gpio_direction_output(unsigned gpio, int value);
  • gpio:要设置的 GPIO 编号。
  • value:初始输出电平,0 表示低电平,1 表示高电平。 返回值:成功时返回 0,失败时返回负数错误码。

3、设置 GPIO 输出电平

void gpio_set_value(unsigned gpio, int value);
  • gpio:要设置的 GPIO 编号。
  • value:要设置的输出电平,0 表示低电平,1 表示高电平。

4、读取 GPIO 输入电平

int gpio_get_value(unsigned gpio);
  • gpio:要读取的 GPIO 编号。
  • 返回值:成功时返回 0 或 1,表示输入电平的高或低电平。失败时返回负数错误码。

5、释放 GPIO

void gpio_free(unsigned gpio);
  • gpio:要释放的 GPIO 编号。

例程

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>

#define MY_GPIO_PIN 17

static int __init my_gpio_init(void)
{
    int ret;

    ret = gpio_request(MY_GPIO_PIN, "my_gpio");
    if (ret) {
        printk(KERN_ERR "Failed to request GPIO %d\n", MY_GPIO_PIN);
        return ret;
    }

    ret = gpio_direction_output(MY_GPIO_PIN, 1);
    if (ret) {
        printk(KERN_ERR "Failed to set GPIO %d as output\n", MY_GPIO_PIN);
        gpio_free(MY_GPIO_PIN);
        return ret;
    }

    gpio_set_value(MY_GPIO_PIN, 0);
    printk(KERN_INFO "GPIO %d set to low level\n", MY_GPIO_PIN);

    return 0;
}

static void __exit my_gpio_exit(void)
{
    gpio_free(MY_GPIO_PIN);
    printk(KERN_INFO "GPIO %d freed\n", MY_GPIO_PIN);
}

module_init(my_gpio_init);
module_exit(my_gpio_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ygc");

4.8之后的内核改动

从 Linux 内核 4.8 版本开始,引入了更现代的 GPIO 子系统,使用 gpiod_* 系列函数,相关函数定义在 <linux/gpio/consumer.h> 头文件中

1、获取 GPIO 描述符

#include <linux/gpio/consumer.h>

struct gpio_desc *gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags);
  • dev:关联的设备结构体指针。
  • con_id:GPIO 控制器的连接标识符。
  • flags:标志位,例如 GPIOD_OUT_LOW 或 GPIOD_OUT_HIGH 用于设置初始输出电平。 返回值:成功时返回 GPIO 描述符指针,失败时返回 ERR_PTR。

2、设置 GPIO 输出电平

void gpiod_set_value(struct gpio_desc *desc, int value);
  • desc:GPIO 描述符指针。
  • value:要设置的输出电平,0 表示低电平,1 表示高电平。

3、释放 GPIO 描述符

void gpiod_put(struct gpio_desc *desc);

释放 GPIO 描述符,释放 GPIO 描述符后,GPIO 描述符将不再可用。

例程

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio/consumer.h>

static struct gpio_desc *my_gpio_desc;

static int __init my_gpio_init_new(void)
{
    my_gpio_desc = gpiod_get(NULL, "my_gpio", GPIOD_OUT_LOW);
    if (IS_ERR(my_gpio_desc)) {
        printk(KERN_ERR "Failed to get GPIO descriptor\n");
        return PTR_ERR(my_gpio_desc);
    }

    gpiod_set_value(my_gpio_desc, 1);
    printk(KERN_INFO "GPIO set to high level\n");

    return 0;
}

static void __exit my_gpio_exit_new(void)
{
    gpiod_put(my_gpio_desc);
    printk(KERN_INFO "GPIO descriptor freed\n");
}

module_init(my_gpio_init_new);
module_exit(my_gpio_exit_new);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("YGC");