单片机
返回首页

linux驱动(七)gpiolib库详解

2025-01-07 来源:cnblogs

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


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


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章