分享

内核里的gpiolib在终端上命令操作gpio口

 slimfeng 2019-09-20

内核里的gpiolib除了提供如gpio_request, gpio_direction_input/output, gpio_set_value等操作函数外,还提供了在终端上用直接操作gpio口的功能.

首先确认内核里是否已选择上gpiolib的sysfs接口功能(默认是已选择上的)

make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
  Device Drivers  --->
    *- GPIO Support  --->
        [*]   /sys/class/gpio/... (sysfs interface)

然后确认在linux内核源码里gpio口对应的序号,这个是由芯片厂家自定义的,通常在”arch/arm/mach-xxx/include/mach/gpio.h”里.
h3的gpio口定义在”arch/arm/mach-sunxi/include/mach/gpio.h”

#define SUNXI_BANK_SIZE 32
#define SUNXI_PA_BASE   0
#define SUNXI_PB_BASE   32
#define SUNXI_PC_BASE   64
#define SUNXI_PD_BASE   96
#define SUNXI_PE_BASE   128
#define SUNXI_PF_BASE   160
#define SUNXI_PG_BASE   192
#define SUNXI_PH_BASE   224
#define SUNXI_PI_BASE   256
#define SUNXI_PJ_BASE   288
#define SUNXI_PK_BASE   320
#define SUNXI_PL_BASE   352
#define SUNXI_PM_BASE   384
#define SUNXI_PN_BASE   416
#define SUNXI_PO_BASE   448
#define AXP_PIN_BASE    1024

#define SUNXI_PIN_NAME_MAX_LEN  8

/* sunxi gpio name space */
#define GPIOA(n)    (SUNXI_PA_BASE + (n))
#define GPIOB(n)    (SUNXI_PB_BASE + (n))
#define GPIOC(n)    (SUNXI_PC_BASE + (n))
#define GPIOD(n)    (SUNXI_PD_BASE + (n))
#define GPIOE(n)    (SUNXI_PE_BASE + (n))
#define GPIOF(n)    (SUNXI_PF_BASE + (n))
#define GPIOG(n)    (SUNXI_PG_BASE + (n))
#define GPIOH(n)    (SUNXI_PH_BASE + (n))
#define GPIOI(n)    (SUNXI_PI_BASE + (n))
#define GPIOJ(n)    (SUNXI_PJ_BASE + (n))
#define GPIOK(n)    (SUNXI_PK_BASE + (n))
#define GPIOL(n)    (SUNXI_PL_BASE + (n))
#define GPIOM(n)    (SUNXI_PM_BASE + (n))
#define GPION(n)    (SUNXI_PN_BASE + (n))
#define GPIOO(n)    (SUNXI_PO_BASE + (n))
#define GPIO_AXP(n) (AXP_PIN_BASE  + (n))

gpio口的操作过程,如控制status-led(接在PA15)的亮灭.

1 让gpiolib导出PA15的控制文件. 可根据上面检出PA15引脚对应的gpio口序号为15
    echo 15 > /sys/class/gpio/export

   操作完成后,应会在/sys/class/gpio/目录下生成一个gpio15的子目录.

2  在/sys/class/gpio/gpio15目录有文件:
    /mnt/kernel_coding # ls /sys/class/gpio/gpio15/
    active_low  direction  edge   value

   //通过direction文件可控制gpio口是作输入或输出功能
    // echo "high" > /sys/class/gpio/gpio15/direction   是让gpio口作输出,并输出高电平
    // echo "out"  > /sys/class/gpio/gpio15/direction   是作输出功能,并输出低电平
    // echo "in"   > /sys/class/gpio/gpio15/direction   是作输入功能
   //通过value文件可以获取和控制gpio口的电平(当gpio口作输出时,可以通过写操作改变电平。当作输入时,可以通过读操作获取电平) 
    // echo "1" > /sys/class/gpio/gpio15/value    让gpio口输出高电平
    // echo "0" > /sys/class/gpio/gpio15/value    让gpio口输出低电平
   //通过edge文件, 可以指定gpio作中断功能,并指定它的触发电平和获取. 触发电平方式有("none", "falling", "rising", "both")

   //通过active_low文件,可以指定往value文件写1时为有效电平.
    如: echo "1" > /sys/calss/gpio/gpio15/value时是输出高电平的
       当echo "1" > /sys/calss/gpio/gpio15/active_low后, 再往value写1是就是输出低电平了.


工作原理可参考https://blog.csdn.net/jklinux/article/details/73896459

702 static struct class_attribute gpio_class_attrs[] = {
 703     __ATTR(export, 0200, NULL, export_store),  // 当对/sys/class/gpio/export进行写操作时,会触发调用export_store函数
 704     __ATTR(unexport, 0200, NULL, unexport_store),
 705     __ATTR_NULL,
 706 };
 707 
 708 static struct class gpio_class = {
 709     .name =     "gpio",
 710     .owner =    THIS_MODULE,
 711 
 712     .class_attrs =  gpio_class_attrs, //指定了属性文件. (/sys/class/gpio/export,  /sys/class/gpio/unexport)
 713 };


 997 static int __init gpiolib_sysfs_init(void)
 998 {
        ...
1003     status = class_register(&gpio_class); //注册class后就会生成/sys/class/gpio目录,并在目录下生成gpio_class的属性文件
        ...
1029 }
1030 postcore_initcall(gpiolib_sysfs_init); //系统初始化时会调用

//当对"echo gpio口对应的序号 > /sys/class/gpio/export"进行写操作时,会触发调用export_store函数
 637 static ssize_t export_store(struct class *class,
 638                 struct class_attribute *attr,
 639                 const char *buf, size_t len)
 640 {
 641     long    gpio;
 642     int status;
 643 
 644     status = strict_strtol(buf, 0, &gpio); //把字符串buf里描述的gpio口序号转成long类型变量gpio
        ...
 653     status = gpio_request(gpio, "sysfs"); //请求gpio口
        ...
 659     status = gpio_export(gpio, true); //再调用gpio_export函数来处理请求的gpio口
        ...
 669 }


 731 int gpio_export(unsigned gpio, bool direction_may_change)
 732 {
        ...
 774     dev = device_create_with_groups(&gpio_class, desc->chip->dev,
 775                     MKDEV(0, 0), desc, gpio_groups,
 776                     ioname ? ioname : "gpio%u", gpio); //会在/sys/class/gpio/目录下生成一个名为"gpio"+gpio口序号的子目录(请gpio口为15, 则子目录名为"gpio15"), 并在子目录生成"direction, edge,value, active_low"等属性文件
        ...
 790 }
 791 EXPORT_SYMBOL_GPL(gpio_export);

 571 static struct attribute *gpio_attrs[] = {
 572     &dev_attr_direction.attr,
 573     &dev_attr_edge.attr,
 574     &dev_attr_value.attr,
 575     &dev_attr_active_low.attr,
 576     NULL,
 577 };
 578 
 579 static const struct attribute_group gpio_group = {
 580     .attrs = gpio_attrs,
 581     .is_visible = gpio_is_visible,
 582 };
 583 
 584 static const struct attribute_group *gpio_groups[] = {
 585     &gpio_group,
 586     NULL
 587 };


///////////////////////////////////
 242 static ssize_t gpio_direction_store(struct device *dev,
 243         struct device_attribute *attr, const char *buf, size_t size)
 244 {
 245     const struct gpio_desc  *desc = dev_get_drvdata(dev);
 246     unsigned        gpio = desc - gpio_desc;
 247     ssize_t         status;
 248 
 249     mutex_lock(&sysfs_lock);
 250 
 251     if (!test_bit(FLAG_EXPORT, &desc->flags))
 252         status = -EIO;
 253     else if (sysfs_streq(buf, "high"))
 254         status = gpio_direction_output(gpio, 1);
 255     else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
 256         status = gpio_direction_output(gpio, 0);
 257     else if (sysfs_streq(buf, "in"))
 258         status = gpio_direction_input(gpio);
 259     else
 260         status = -EINVAL;
 261 
 262     mutex_unlock(&sysfs_lock);
 263     return status ? : size;
 264 }
 265 
 266 static DEVICE_ATTR(direction, 0644,
 267         gpio_direction_show, gpio_direction_store); // 当对direction属性文件写操作时,触发调用gpio_direction_store. 如写"out"则把gpio口作为输出,并输出低电平. 同样的原理,可以通过value属性文件操作gpio口的电平状态.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多