• linux驱动(七)gpiolib库详解


    ---恢复内容开始---

    1:什么是gpiolib,为什么要有gpiolib?

    linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作用是对所有的gpio实行统一管理,因为驱动在工作的时候,会出现好几个驱动共同使用同一个gpio的情况;

    这会造成混乱。所以内核提供了一些方法来管理gpio资源;

    2:如何学习gpiolib

    第一:gpiolib库的建立;

    第二:gpiolib库的使用方法:申请、使用、释放;

    3:

      我们首先来看一下这个文件:mach-smdkc110.c这个文件:

    smdkc110_map_io

        s5pv210_gpiolib_init  这个函数是gpiolib的初始化函数

    __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;
    }

    gpiolib库的初始化实质就是对这个结构体数组进行赋值;

    下面看一下这个结构体

    struct s3c_gpio_chip {
        struct gpio_chip    chip;
        struct s3c_gpio_cfg    *config;
        struct s3c_gpio_pm    *pm;
        void __iomem        *base;
        int            eint_offset;
        spinlock_t         lock;
    #ifdef CONFIG_PM
        u32            pm_save[7];
    #endif
    };

     chpi结构体:为主要结构体

    关键几个元素

    label

    request    //申请gpio

    free      //释放gpio

    direction_input    //输入模式

    direction_output    //输出模式

    get          //读取gpio的值

    set          //写入gpio的值

    base        //gpio基地址 端口地址

    ngpio        //引脚地址

    names        //名字

     
    struct gpio_chip {
        const char        *label;
        struct device        *dev;
        struct module        *owner;
    
        int            (*request)(struct gpio_chip *chip,
                            unsigned offset);
        void            (*free)(struct gpio_chip *chip,
                            unsigned offset);
    
        int            (*direction_input)(struct gpio_chip *chip,
                            unsigned offset);
        int            (*get)(struct gpio_chip *chip,
                            unsigned offset);
        int            (*direction_output)(struct gpio_chip *chip,
                            unsigned offset, int value);
        int            (*set_debounce)(struct gpio_chip *chip,
                            unsigned offset, unsigned debounce);
    
        void            (*set)(struct gpio_chip *chip,
                            unsigned offset, int value);
    
        int            (*to_irq)(struct gpio_chip *chip,
                            unsigned offset);
    
        void            (*dbg_show)(struct seq_file *s,
                            struct gpio_chip *chip);
        int            base;
        u16            ngpio;
        const char        *const *names;
        unsigned        can_sleep:1;
        unsigned        exported:1;
    };

     

    内核中建立了

    static struct s3c_gpio_chip s5pv210_gpio_4bit[] 这个数组,将所有的gpio的.chip结构体中的一些元素初始化

     这个数组的所有元素是与数据手册中的所有gpio是一一对应的;

     我们首先来分析一下.chip->base中的值 通过一下几个宏定义我们可以知道gpa0中 chip->.chip->base中的值为 0 gpa1中chip->.chip->base中的值为9 这个数字数对应端口的io口的号码;

    #define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
    #define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr)) 

    S5PV210_GPIO_A0_START = 0,
    S5PV210_GPIO_A1_START = S5PV210_GPIO_NEXT(S5PV210_GPIO_A0),

    #define S5PV210_GPIO_NEXT(__gpio)
    ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1) 

    #define S5PV210_GPIO_A0_NR (8)
    #define S5PV210_GPIO_A1_NR (4)
    #define S5PV210_GPIO_B_NR (8)
    #define S5PV210_GPIO_C0_NR (5)

     ----------------------------------------------------------------------------------------------------------------------------------------------

     接下来是对

    chip->config = &gpio_cfg;

    chip->config结构体赋值;

    然后是对chip->base 赋值

    chip->base = S5PV210_BANK_BASE(i);

     #define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)

     可以看出chip->base是把gpio的虚拟地址赋值给chip->base,每个gpio的地址差0x20;

     下面看一下

    samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_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);
            s3c_gpiolib_add(chip);
        }
    }

    这个函数中调用了两个函数

    samsung_gpiolib_add_4bit_chips

        samsung_gpiolib_add_4bit

        s3c_gpiolib_add

    void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
    {
        chip->chip.direction_input = samsung_gpiolib_4bit_input;
        chip->chip.direction_output = samsung_gpiolib_4bit_output;
        chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
    }

    这个函数的作用是对每个chip->chip的direction_input direction_output两个函数赋值

    下面看一下s3c_gpiolib_add函数都做了什么:

        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;

    继续对chip->中的元素进行赋值,set get赋值,

    ret = gpiochip_add(gc);

    最后注册这些gpio_chip结构体;

    注册的实质是:在linux内核中有一个gpio_desc结构体数组,注册就是把我们封装的gpio的所有信息的结构体放到数组的格子中;

    static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];   

    gpiolib库是linux内核工程师以及三星芯片厂商工程师共同完成的,内核工程师提供搭建好底层框架,三星工程师

    把自己开发板的gpio初始化并注册到内核提供的数组中去;

    ---------------------------------------------------------------------------------------------------------------

    上面讲了gpiolib库的构建,构建的实质是把所有的gpio结构体进行初始化,并且放到内核中gpio_desc这个结构体数组中;

    下面看一下我们在开发驱动的时候如何使用gpiolib库

    首先要了解一下linux内核工程师给我们开发的接口:
    文件:/drivers/gpio/gpiolib.c文件中提供所有的接口

    1:gpio_request:向内核申请gpio

    int gpio_request(unsigned gpio, const char *label)

    2:gpio_free对应gpio_request,是使用完gpio以后把gpio释放掉

    void gpio_free(unsigned gpio)

    3:gpiochip_add:向内核注册gpio

    int gpiochip_add(struct gpio_chip *chip)

    4:gpio_request_one  申请gpio

    int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)

    5:gpio_request_one申请gpio

    int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)

    6:gpiochip_is_requested:用来看gpio是否已经使用

    const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)

    7:gpio_direction_input :设置gpio输入

    int gpio_direction_input(unsigned gpio)

    8:gpio_direction_output:gpio输出

    int gpio_direction_output(unsigned gpio, int value)

    9:__gpio_get_value :获取寄存器的值    这里注意由于前面加了__是内核用的函数所以我们不能用这个函数

    在/arch/arm/mach-s5pv210/include/mach/gpio.h中定义了以下宏;所以我们使用的时候直接包含这个头文件使用gpio_get_value 函数即可

    #define gpio_get_value __gpio_get_value
    #define gpio_set_value __gpio_set_value
    #define gpio_cansleep __gpio_cansleep
    #define gpio_to_irq __gpio_to_irq

    int __gpio_get_value(unsigned gpio)

    10:__gpio_get_value :设置寄存器的值

    int __gpio_get_value(unsigned gpio)

    http://blog.csdn.net/tongxinv/article/details/54790792

    ---------------------------------------------------------------------------------------------------------------------------------

    代码实战:

  • 相关阅读:
    (Java随机数举例)随机扔一千次硬币的正反次数
    hibernate+spring的整合思路加实例(配图解)
    从零开始学C++之IO流类库(三):文件的读写、二进制文件的读写、文件随机读写
    ssh连接Linux自动断开后再也无法连上的问题
    面试题10:二进制中1的个数
    C 语言统计关键字出现次数
    在Eclipse中Attach Source
    Visual Sudio 2012转换界面风格
    java 判断字符串IP合法性以及获取IP的数值形式
    java.lang.string split 以点分割字符串无法正常拆分字符串
  • 原文地址:https://www.cnblogs.com/biaohc/p/6652322.html
Copyright © 2020-2023  润新知