zoukankan      html  css  js  c++  java
  • gpiolib库详解

    /************************************************************************************

    *本文为个人学习记录,如有错误,欢迎指正。

    *本文参考资料: 

    *        https://www.cnblogs.com/wenhuisun/archive/2013/04/11/3013951.html

    *        https://www.cnblogs.com/biaohc/p/6652322.html

    *        https://blog.csdn.net/andrinux/article/details/38725619

    ************************************************************************************/

    1. gpiolib库简介

    linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作用是对所有的gpio实行统一管理,因为驱动在工作的时候,会出现好几个驱动共同使用同一个gpio的情况;这会造成混乱。所以内核提供了一些方法来管理gpio资源。

    2. gpiolib库的建立

    gpiolib库建立的目标函数:

    //所在文件:/kernel/arch/arm/mach-s5pv210/mach-smdkc110.c
    static void __init smdkc110_map_io(void)
    {
        ......
        s5pv210_gpiolib_init();
        ......
    }
    
    
    //所在文件:/kernel/arch/arm/mach-s5pv210/gpiolib.c
    __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;
    }

     s5pv210_gpiolib_init()函数分析:

    (1)gpiolib库的初始化实质就是对s3c_gpio_chip结构体数组进行赋值;struct s3c_gpio_chip用以描述一个GPIO端口。

    struct s3c_gpio_chip 
    {
        struct gpio_chip    chip;  
        struct s3c_gpio_cfg *config;
        struct s3c_gpio_pm  *pm;
        void __iomem        *base;  //存放GPIO的虚拟地址
        int            eint_offset;
        spinlock_t         lock;
    #ifdef CONFIG_PM
        u32            pm_save[7];
    #endif
    };
    
    struct gpio_chip 
    {
      ......
      const char  *label; //GPIO端口名称
      int  base;         //GPIO端口号
      ......
    }

    (2)内核中建立了static struct s3c_gpio_chip s5pv210_gpio_4bit[] 这个数组,将所有的gpio的.chip结构体中的一些元素初始化,这个数组的所有元素是与数据手册中的所有gpio是一一对应的。

    static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
        {
            .chip    = {
                .base    = S5PV210_GPA0(0),
                .ngpio    = S5PV210_GPIO_A0_NR,
                .label    = "GPA0",
                .to_irq = s5p_gpiolib_gpioint_to_irq,
            },
        }, {
            .chip    = {
                .base    = S5PV210_GPA1(0),
                .ngpio    = S5PV210_GPIO_A1_NR,
                .label    = "GPA1",
                .to_irq = s5p_gpiolib_gpioint_to_irq,
            },
        }, {
            .chip    = {
                .base    = S5PV210_GPB(0),
                .ngpio    = S5PV210_GPIO_B_NR,
                .label    = "GPB",
                .to_irq = s5p_gpiolib_gpioint_to_irq,
            },
        }, 
           ......
    }

    .chip.base是GPIO的编号,用宏定义表示。S5PV210_GPA0(0)宏解析如下,即S5PV210_GPA0(0) = 0,S5PV210_GPA0(1) = 1。

    #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)

    (3)chip->base = S5PV210_BANK_BASE(i),将GPIO的虚拟地址写入。

     //每个gpio的地址差0x20
    #define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)

    (4)samsung_gpiolib_add_4bit_chips()函数的作用是将所有GPIO向内核注册。注册的实质是:在linux内核中有一个gpio_desc结构体数组,注册就是把我们封装的gpio的所有信息的结构体放到数组的格子中。

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

    3. gpiolib库的使用

    (1)申请GPIO

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *        const char *label:GPIO名称
    *返回值:
    *        返回值为0,GPIO申请成功;否则,GPIO申请失败
    */
    int gpio_request(unsigned gpio, const char *label); 

    (2)设置GPIO方向

    1)设置为输入

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *返回值:
    *        返回值为<0,设置失败
    */
    int gpio_direction_input(unsigned gpio);

    2)设置为输出

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *        int value:GPIO输出值
    *返回值:
    *        返回值为<0,设置失败
    */
    int gpio_direction_output(unsigned gpio, int value);

    (3)获取/设置GPIO的值

    a. 可睡眠

    对于有些挂载在I2C,SPI总线上的扩展GPIO,读写操作可能会导致睡眠,因此不能在中断函数中使用可睡眠操作。使用下面的函数以区别于正常的GPIO:

    1)获取GPIO的值

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *返回值:
    *        返回GPIO的值,0或1
    */
    int gpio_get_value_cansleep(unsigned gpio);

    2)设置GPIO的值

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *        int value:GPIO设置值
    *返回值:
    *        无
    */
    void gpio_set_value_cansleep(unsigned gpio, int value);

    b. 不可睡眠

    1)获取GPIO的值

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *返回值:
    *        返回GPIO的值,0或1
    */
    int gpio_get_value(unsigned gpio);

    2)设置GPIO的值

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *        int value:GPIO设置值
    *返回值:
    *        无
    */
    void gpio_set_value(unsigned gpio, int value);

    (4)释放GPIO

    /*
    *参数:
    *        unsigned gpio:GPIO编号
    *返回值:
    *        无
    */
    void gpio_free(unsigned gpio);

    (5)批量初始化/释放GPIO

    1)批量初始化GPIO

    /*
    *参数:
    *        unsigned gpio  *array:GPIO数组(多个GPIO编号)
    *        size_t num:GPIO数组大小,GPIO即的个数
    *返回值:
    *        返回0,初始化成功;否则,初始化失败
    */
    int gpio_request_array(struct gpio *array, size_t num);

    2)批量释放GPIO

    /*
    *参数:
    *        unsigned gpio  *array:GPIO数组(多个GPIO编号)
    *        size_t num:GPIO数组大小,GPIO即的个数
    *返回值:
    *        无
    */
    void gpio_free_array(struct gpio *array, size_t num);

     4. S3C平台的GPIO操作接口

    kernel/arch/arm/plat-s3c/include/plat/gpio-cfg.h文件中提供了S3C平台的GPIO操作接口,以下列举一些常用的GPIO操作接口。

    (1)GPIO的工作模式设置

    Linux内核中GPIO的工作模式的定义。

    /*
    *GPIO的工作模式定义
    */
    #define S3C_GPIO_INPUT    (S3C_GPIO_SPECIAL(0))   //输出模式
    #define S3C_GPIO_OUTPUT   (S3C_GPIO_SPECIAL(1))   //输入模式
    #define S3C_GPIO_SFN(x)   (S3C_GPIO_SPECIAL(x))   //其他模式,根据参数x决定

    S3C_GPIO_SFN(x)中x的值对应的功能可通过数据手册来查阅。譬如,根据D5PV210的数据手册可知:

    /*
    *x = 0,GPH0_0为输入模式
    *x = 1,GPH0_0为输出模式
    *x = 0x0f,GPH0_0为外部中断模式
    */
    
    S3C_GPIO_SFN(0)   //输入模式 
    S3C_GPIO_SFN(1)   //输出模式 
    S3C_GPIO_SFN(0x0f)//外部中断模式 

    1)s3c_gpio_cfgpin()设置指定引脚的工作模式

    /*
    *功能:设置指定引脚的工作模式
    *参数:
    *        unsigned int pin:需要设置的引脚号
    *        unsigned int to:需要设置的工作模式
    */
    int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
    
    s3c_gpio_cfgpin(S5PV210_GPA0(0), S3C_GPIO_SFN(0));   //设置GPH0_0为输入模式 
    s3c_gpio_cfgpin(S5PV210_GPA0(0), S3C_GPIO_SFN(1));   //设置GPH0_0为输出模式 
    s3c_gpio_cfgpin(S5PV210_GPA0(0), S3C_GPIO_SFN(0x0f));//设置GPH0_0为外部中断模式

    2)s3c_gpio_getcfg()读取指定引脚的设置值

    /*
    *功能:读取指定引脚的设置值
    *参数:
    *        unsigned int pin:需要获取的引脚号
    *返回值:获取G引脚工作模式的值
    */
    unsigned s3c_gpio_getcfg(unsigned int pin);

     3)s3c_gpio_cfgin_range()批量设置多个引脚的工作模式

    /*
    *功能:批量设置多个引脚的工作模式
    *参数:
    *        unsigned int start:起始引脚号
    *        unsigned int nr:   需要设置的引脚个数
    *        unsigned int cfg:  需要设置的工作模式
    */
    int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, unsigned int cfg);

     (2)GPIO的上下拉设置

     Linux内核中,上下拉的状态值的定义。

    #define S3C_GPIO_PULL_NONE  ((__force s3c_gpio_pull_t)0x00)  //关闭,上拉下拉都关闭
    #define S3C_GPIO_PULL_DOWN  ((__force s3c_gpio_pull_t)0x01)  //下拉
    #define S3C_GPIO_PULL_UP    ((__force s3c_gpio_pull_t)0x02)  //上拉

     1)s3c_gpio_setpull()设置GPIO引脚的上下拉使能

    /*
    *功能:设置单个引脚的上下拉模式
    *参数:
    *        unsigned int pin:需要设置的引脚
    *        s3c_gpio_pull_t pull:上下拉的状态值
    */
    int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull);

     2)s3c_gpio_getpull()读取指定引脚的上下拉状态

    /*
    *功能:读取指定引脚的上下拉状态
    *参数:
    *        unsigned int pin:需要读取的引脚
    *返回值:        
    *        s3c_gpio_pull_t :上下拉的状态值
    */
    s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin);

    3) s3c_gpio_cfgall()批量设置多个引脚的工作模式和上下拉状态

    /*
    *功能:批量设置多个引脚的工作模式和上下拉状态
    *参数:
    *       unsigned int start:  起始引脚号
    *       unsigned int nr:     需要设置的引脚个数
    *       unsigned int cfg:    需要设置的引脚工作模式
    *       s3c_gpio_pull_t pull:需要设置的引脚的上下拉状态
    */
    int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, unsigned int cfg, s3c_gpio_pull_t pull);
  • 相关阅读:
    设置C#Web网页Session超时丢失时间
    docker19.03限制容器使用的cpu资源
    centos8平台搭建mysql8数据库主从同步
    centos8平台使用slabtop监控slab内存的状态
    centos8上使用lsblk查看块设备
    centos8环境判断当前操作系统是否虚拟机或容器
    centos8平台使用lscpu查看cpu信息
    centos8平台使用pidstat监控cpu/内存/io
    docker19.03使用数据卷
    testng对失败时截图处理
  • 原文地址:https://www.cnblogs.com/linfeng-learning/p/9450478.html
Copyright © 2011-2022 走看看