1. 程式人生 > >驅動學習之gpiolib的建立過程

驅動學習之gpiolib的建立過程

linux驅動 gpiolib

1:gpiolib的學習重點

(1)gpiolib的建立過程:gpiolib和虛擬地址映射類似,也是需要一個建立

過程的,因此在學習的時候,我們需要明白gpiolib是什麽時候建立的,建立函數在哪被調用的。

(2)gpiolib的使用方法:申請、使用、釋放

(3)gpiolib的架構:涉及哪些目錄的哪些文件

2:什麽是gpiolib,為什麽需要使用gpiolib

linux中從2.6.35以後就開始有gpiolib庫了,gpiolib的作用是對所有的gpio實行統一管理,因為驅動在工作的時候,會出現好幾個驅動共同使用同一個gpio的情況;這會造成混亂。所以內核提供了一些方法來管理gpio資源;


3:gpiolib的初始化函數

在我們的mach-smdkc110.c文件中的

smdkc110_map_io

s5pv210_gpiolib_init 這個函數是gpiolib的初始化函數

smdkc110_map_io這個函數的調用過程,在我們分析靜態映射的時候已經分析了。

4結構體struct s3c_gpio_chip

struct s3c_gpio_chip
 {
    struct gpio_chipchip;
    struct s3c_gpio_cfg*config;
    struct s3c_gpio_pm*pm;
    void __iomem*base;
    inteint_offset;
    spinlock_t lock;
    #ifdef CONFIG_PM
    u32pm_save[7];
    #endif
};

(1)這個結構體在arch/arm/palt-samsung/include/plat/gpio-core.h中

(2)一個s3c_gpio_chip結構體類型的變量就可以用來描述一個gpio端口(註意這裏是一個端口,而不是一個IO口,一個端口裏面可以有多個IO口(一般是一個端口有8個IO))

(3)需要struct gpio_chip結構體中的元素

const char *label;

這個元素是用來記錄當前IO坐在的IO端口的名字,比如IO口GPA0.0所在的IO端口就是GPA0

(4)int base;

當前IO口所屬的IO端口的編號,我們的gpiolib中 記錄IO的方法是通過記錄每一組IO的端口基礎編號,然後通過一個IO的端口就在這個基準端口上疊加即可。

比如:

端口GPA0共有8個IO,IO口編號為0 -7,那麽基準號就是0,也就是base = 0;

端口GPA1共有4個IO,IO口編號為8-11,那麽基準號就是8,也就是base = 8;

5:s5pv210_gpio_4bit

(1)s5pv210_gpio_4bit是一個s3c_gpio_chip類型的結構體數組。

(2)將所有的gpio的.chip結構體中的一些元素初始化,這個數組的所有元素是與數據手冊中的所有gpio是一一對應的。

(4)分析可知,這個數組就是對當前MPU中的所有的IO端口和每個端口的IO口進行了統一的描述,有了這個數組, 我們就知道當前開發板有多少個端口,有多少個IO口,以及每個IO口的編號。


6:s5pv210_gpiolib_init

__init int s5pv210_gpiolib_init(void)
{
    struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
    int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
    int i = 0;
    for (i = 0; i < nr_chips; i++, chip++)
     {
        if (chip->config == NULL)
        chip->config = &gpio_cfg;
        if (chip->base == NULL)
        chip->base = S5PV210_BANK_BASE(i);
    }
    samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);

    return 0;
}



(1)通過上面的分析可知,s5pv210_gpiolib_init這個函數的作用是將我們開發板中所有GPIO的端口進行一個配置,並且為所有GPIO端口分配一個基準端口的虛擬地址,通過這個基準地址就能得到這組端口中所有IO口的寄存器的地址。

(2)我們之前講過,在我們的s5pv210_gpio_4bit這個數組中綁定了開發板中所有IO口的信息,int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);得到我們s5pv210_gpio_4bit數組的元素個數,然後調用samsung_gpiolib_add_4bit_chips這個函數,將開發板中的所有信息向我們的系統進行註冊,這樣系統就能知道當前系統中的所以IO口的信息。

7:samsung_gpiolib_add_4bit_chips

void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,int nr_chips)
{
    for (; nr_chips > 0; nr_chips--, chip++)
     {
        samsung_gpiolib_add_4bit(chip);   //這裏的chip指針+1實際上加的是一個元素
        s3c_gpiolib_add(chip);
    }
}

(1)經過分析,發現samsung_gpiolib_add_4bit內部其實並沒有做gpiolib的註冊工作,而是還在做填充,填充的是每一個GPIO被設置成輸入模式/輸出模式的操作方法。

(2)s3c_gpiolib_add

__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
    struct gpio_chip *gc = &chip->chip;
    int ret;
    BUG_ON(!chip->base);
    BUG_ON(!gc->label);
    BUG_ON(!gc->ngpio);
    spin_lock_init(&chip->lock);
    if (!gc->direction_input)
    gc->direction_input = s3c_gpiolib_input;
    if (!gc->direction_output)
    gc->direction_output = s3c_gpiolib_output;
    if (!gc->set)
    gc->set = s3c_gpiolib_set;
    if (!gc->get)
    gc->get = s3c_gpiolib_get;
    #ifdef CONFIG_PM
    if (chip->pm != NULL) 
    {
        if (!chip->pm->save || !chip->pm->resume)
        printk(KERN_ERR "gpio: %s has missing PM functions\n",gc->label);
    } 
    else
        printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
    #endif
    /* gpiochip_add() prints own failure message on error. */
    ret = gpiochip_add(gc);
    if (ret >= 0)
    s3c_gpiolib_track(chip);
}

(1)首先我們在前面的分析可知,在samsung_gpiolib_add_4bit函數中,已經添加了我們的input和output方法,所以這裏的if不會成立,並且分析函數可知,這裏掛接的input和output方法是針對2bit的CON寄存器的芯片(2440)。

(2)這個函數首先是對我們的GPIO進行進一步的填充,主要是添加set和get的方法。

(3)調用gpiochip_add函數來完成真真的註冊。



驅動學習之gpiolib的建立過程