Linux Kernel gpio export功能

一、前言

在正常情况下,假设我们在控制usb使能相关gpio脚的时候,代码中通常我们会做如下调用:

#define USB_EN_GPIO        11

gpio_request(USB_EN_GPIO, "usb_en");
gpio_direction_output(USB_EN_GPIO, 1);
gpio_export(USB_EN_GPIO, false);

上述执行完毕之后就可以给 GPIO_11 这个口上电,并且会生成 sysfs相关的控制节点。这里是/sys/class/gpio/gpio11/的目录,该目录下的内容为:

-rw-r--r-- 0        0              4096 1970-01-01 01:38 active_low
-rw-r--r-- 0        0              4096 1970-01-01 01:38 direction
drwxr-xr-x 0        0                   1970-01-01 00:00 power
lrwxrwxrwx 0        0                   1970-01-01 01:38 subsystem -> ../../../../class/gpio
-rw-r--r-- 0        0              4096 1970-01-01 00:00 uevent
-rw-r--r-- 0        0              4096 1970-01-01 01:38 value

调用 gpio_export() 就可以生成该GPIO相关的sysfs控制节点。


二、gpio_export()

1、函数定义:

// include/asm-generic/gpio.h

/*
 * A sysfs interface can be exported by individual drivers if they want,
 * but more typically is configured entirely from userspace.
 */
static inline int gpio_export(unsigned gpio, bool direction_may_change)
{
    return gpiod_export(gpio_to_desc(gpio), direction_may_change);
}

2、gpiod_export()定义

drivers/gpio/gpiolib.c

/**
 * gpiod_export - export a GPIO through sysfs
 * @gpio: gpio to make available, already requested
 * @direction_may_change: true if userspace may change gpio direction
 * Context: arch_initcall or later
 *
 * When drivers want to make a GPIO accessible to userspace after they
 * have requested it -- perhaps while debugging, or as part of their
 * public interface -- they may use this routine.  If the GPIO can
 * change direction (some can't) and the caller allows it, userspace
 * will see "direction" sysfs attribute which may be used to change
 * the gpio's direction.  A "value" attribute will always be provided.
 *
 * Returns zero on success, else an error.
 */
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)

参数 @gpio 用于指定是哪个gpio;
参数 @direction_may_change 用来标记这个gpio的输入输出方向是否可以改变;


3、gpiod_export()实现

  • 如果该gpio已经设置了输入或者输出,那么它的direction_may_change为false。
if (!desc->chip->direction_input || !desc->chip->direction_output)
    direction_may_change = false;
  • 创建目录 /sys/class/gpio/gpiox/
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
    desc, ioname ? ioname : "gpio%u",
    desc_to_gpio(desc));
  • 创建目录 /sys/class/gpio/gpio11/ 的相关控制属性
status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
if (status)
    goto fail_unregister_device;

static const struct attribute *gpio_attrs[] = {
    &dev_attr_value.attr,
    &dev_attr_active_low.attr,
    NULL,
};

static const struct attribute_group gpio_attr_group = {
    .attrs = (struct attribute **) gpio_attrs,
};

这里面固定两个属性:active_lowvalue,并且有对应的 show() 和 store() 方法。

  • 如果这个gpio可以设置输入输出方向,那么要创建 direction() 的控制属性
if (direction_may_change) {
    status = device_create_file(dev, &dev_attr_direction);
    if (status)
        goto fail_unregister_device;
}
  • 如果这是一个中断的gpio,那么要创建中断触发边沿 edge() 的控制属性
if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
                   !test_bit(FLAG_IS_OUT, &desc->flags))) {
    status = device_create_file(dev, &dev_attr_edge);
    if (status)
        goto fail_unregister_device;
}

三、/sys/class/gpio/export

比如说我们有个gpio12是用于测试的引脚,比如说用来测量代码的执行时间,在release版本中根本不会像在前言中的代码去request和export它。但是我们又要用使用它,怎么办呢?

  • 方法一就是像前面的那样,在代码中去调用。不过这比较麻烦,还要编译烧录。
  • 另外一个办法就是使用 /sys/class/gpio/export 的功能(也有与之相反的unexport),可以使用#echo 12 > /sys/class/gpio/export 将gpio12 export出来。这样以后在 /sys/class/gpio/ 目录下就会创建 gpio12/ 的目录,并且该目录有相关的对gpio12的操作了。

这个强大的功能由 export_store() 实现。这个是 /sys/class/gpio/ 下 export 的控制属性。

/*
 * /sys/class/gpio/export ... write-only
 *  integer N ... number of GPIO to export (full access)
 * /sys/class/gpio/unexport ... write-only
 *  integer N ... number of GPIO to unexport
 */
static ssize_t export_store(struct class *class,
                struct class_attribute *attr,
                const char *buf, size_t len)

在该函数中分别会调用 gpiod_request()gpiod_export() 为参数 @buf 指定的gpio口申请并且export出来。

status = gpiod_request(desc, "sysfs");
if (status < 0) {
    if (status == -EPROBE_DEFER)
        status = -ENODEV;
    goto done;
}
status = gpiod_export(desc, true);
if (status < 0)
    gpiod_free(desc);
else
    set_bit(FLAG_SYSFS, &desc->flags);

四、gpio sysfs

所有关于gpio sysfs的功能都在 drivers/gpio/gpiolib.c 中实现,入口函数是:gpiolib_sysfs_init()

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值