gpio編號到描述符的轉換

前言

最近在調試一個新板子的LED驅動,LED燈用到了特定的GPIO引腳,而驅動中有一項工作就是需要佔用某個GPIO資源並設置爲輸出引腳,調用的接口類似如下:

#define GPIOAO_3 (3)  /* GPIOAO_3這個引腳的id爲3 */
gpio_request(GPIOAO_3, OWNER_NAME);  /* 佔用GPIOAO_3這個GPIO的資源 */
gpio_direction_output(GPIOAO_3, 0); /* 將GPIOAO_3這個GPIO設置爲輸出引腳並拉低 */

上面的代碼比較常見,應該很多同學都看過類似的,現在問題就來了,爲什麼GPIOAO_3這個GPIO定義爲3呢?這個就是我今天要討論的問題。

正文

前面提出的問題,下面我們會跟着代碼來一步步找出答案。每個平臺都有自己的GPIO驅動,下面我用到的芯片平臺是amlogic s805。雖然代碼有差異,但是基本架構是不變的,一般都從probe函數開始,並調用gpiochip_add()函數將自己的驅動註冊進系統,在這個過程就決定了GPIO的編號到描述符的映射關係。

1、

代碼路徑:

amlogic_gpio_probe:arch\arm\mach-meson8b\gpio.c

函數調用:

struct amlogic_gpio_desc amlogic_pins[]=
{
    PIN_AOMAP(GPIOAO_0,6,0,6,16,6,0),
    PIN_AOMAP(GPIOAO_1,6,1,6,17,6,1),
    PIN_AOMAP(GPIOAO_2,6,2,6,18,6,2),
    PIN_AOMAP(GPIOAO_3,6,3,6,19,6,3),
    PIN_AOMAP(GPIOAO_4,6,4,6,20,6,4),
    ...
};

static int amlogic_gpio_probe(struct platform_device *pdev)
{
    ...
    amlogic_gpio_chip.base=0; /* base這個變量值很重要,奠定了後續gpio編號的起始值 */
    amlogic_gpio_chip.ngpio=ARRAY_SIZE(amlogic_pins); /* amlogic_pins是一個數組,裏面按順序列出了平臺所有的GPIO引腳 */
    gpiochip_add(&amlogic_gpio_chip); /* 註冊進系統 */
    ...
    return 0;
}

2、

代碼路徑:

gpiochip_add:drivers\gpio\gpiolib.c

函數調用:

int gpiochip_add(struct gpio_chip *chip)
{
    ...
    int        base = chip->base;

    if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) /* 判斷編號和GPIO數是否超過了規定的範圍,我這裏是0~256 */
            && base >= 0) {
        status = -EINVAL;
        goto fail;
    }

    spin_lock_irqsave(&gpio_lock, flags);

    if (base < 0) { /* 我這個平臺的base值是0,不會走到下面的分支 */
        base = gpiochip_find_base(chip->ngpio);   -------------------- 2.1小節
        if (base < 0) {
            status = base;
            goto unlock;
        }
        chip->base = base;
    }

    status = gpiochip_add_to_list(chip); /* 將自己平臺的GPIO註冊進系統的鏈表 */

    if (status == 0) {
        chip->desc = &gpio_desc[chip->base]; /* GPIO編號和描述符是一個線性映射的關係,而gpio_desc這個數組就保存這個映射關係,並從base這個偏移位置開始保存每個GPIO的描述符信息 */

        for (id = 0; id < chip->ngpio; id++) { /* 這個for循環裏就爲每一個GPIO描述符賦值 */
            struct gpio_desc *desc = &chip->desc[id]; /* 描述符的首地址指向gpio_desc數組偏移base的位置 */
            desc->chip = chip;
            
            desc->flags = !chip->direction_input
                ? (1 << FLAG_IS_OUT)
                : 0;
        }
    }
    ...
    return status;
}

2.1、

如果你的平臺的base小於0,會走到下面的函數去爲這組GPIO引腳自動分配一個base值

代碼路徑:

gpiochip_add:drivers\gpio\gpiolib.c

函數調用:

static int gpiochip_find_base(int ngpio)
{
    struct gpio_chip *chip;
    int base = ARCH_NR_GPIOS - ngpio; /* ARCH_NR_GPIOS一般是平臺中GPIO數量的最大值 */

    list_for_each_entry_reverse(chip, &gpio_chips, list) { /* 倒序遍歷鏈表(因爲GPIO引腳可能分爲了好幾個bank),目的是找出gpio_desc數組中已經被佔用的位置 */
        /* found a free space? */
        if (chip->base + chip->ngpio <= base) /* 如果已經被佔用的數組位置和準備分配的位置不重合,自然就直接跳出循環了 */
            break;
        else
            /* nope, check the space right before the chip */
            base = chip->base - ngpio;
    }

    if (gpio_is_valid(base)) { /* 檢查是否在規定的範圍內 */
        pr_debug("%s: found new base at %d\n", __func__, base);
        return base;
    } else {
        pr_err("%s: cannot find free range\n", __func__);
        return -ENOSPC;
    }
}

3、

從上面兩步可以看出來,GPIO編號和描述符之間的關係是由gpio_desc這個數組決定的。所以我們想通過GPIO編號找到對應的描述符,就必須知道這個描述符在數組中的偏移位置,而偏移多少可以根據GPIO在amlogic_pins這個數組的位置加上base值得到。

代碼路徑:

drivers\gpio\gpiolib.c

函數調用關係:

gpio_request
    gpiod_request
        gpio_to_desc

static struct gpio_desc *gpio_to_desc(unsigned gpio)
{
    if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
        return NULL;
    else
        return &gpio_desc[gpio]; /* 就是根據傳遞過來的GPIO編號在數組中找到描述符 */
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章