1. 程式人生 > >核心裡的gpiolib在終端上命令操作gpio口

核心裡的gpiolib在終端上命令操作gpio口

核心裡的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是就是輸出低電平了.
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口的電平狀態.