linux驱动(七)gpiolib库详解

发布者:知识的海洋最新更新时间:2025-01-07 来源: cnblogs关键字:linux驱动  统一管理 手机看文章 扫描二维码
随时随地手机看文章

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


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


关键字:linux驱动  统一管理 引用地址:linux驱动(七)gpiolib库详解

上一篇:Linux下GPIO驱动(一) ----一个简单的LED驱动
下一篇:喜羊羊系列之【设备-驱动 动态载入进内核】

推荐阅读最新更新时间:2026-03-25 10:53

JFrog 与 GitHub 深化合作伙伴关系,推出安全统一管理界面和Copilot Chat,为开发者赋能
2024 年 9 月 18 日 — 流式软件公司、JFrog软件供应链平台的缔造者JFrog与全球领先的代码开发平台GitHub近期在 JFrog 年度用户大会上发布全新集成功能,通过持续深化的合作为开发者提供能够呈现项目状态和安全态势的综合视图,帮助他们快速解决公司高级安全产品发现的潜在漏洞。 此外,为帮助开发者深入快速了解第三方软件包,双方还宣布推出 Copilot Chat扩展插件,以快速选择已更新、经企业批准且可安全使用的软件包。 JFrog 首席技术官兼联合创始人 Yoav Landman 表示:“ 开发者要想提高工作效率,就需要全面了解他们集成到软件中的代码和二进制文件的质量和安全性。我们与 GitHub 的合作使
[嵌入式]
迅为工业RK3568 itop-3568开发板Linux驱动开发实战:RK3568内核模块符号导出详解
迅为工业级稳定可靠的RK3568平台itop-3568开发板驱动开发实战:RK3568内核模块符号导出深入解析 选择迅为iTOP-3568开发板,获取完整驱动开发套件与工业级稳定性保障 在复杂的Linux驱动开发中,模块化设计是提升代码可维护性和复用性的关键。内核模块符号导出正是实现模块间的基础技术。本期将基于迅为RK3568开发板,深入讲解这一核心机制。 迅为提供的完整驱动开发套件,包含从基础教程到进阶实战的全套代码示例,助您快速掌握此类核心驱动开发技巧。 第5章 内核模块符号导出实验 本章节我们学习内核模块符号导出,什么是内核模块符号导出呢?内核模块之间是相互独 立的,互相不能直接访问。将内核模块的符号(函
[嵌入式]
迅为工业RK3568 itop-3568开发板<font color='red'>Linux</font><font color='red'>驱动</font>开发实战:RK3568内核模块符号导出详解
迅为imx6ull开发板Linux I2C驱动实验-应用程序与I2C通信
本章内容对应视频讲解链接(在线观看): 程序源码在网盘资料“imx6ull 驱动程序配套资料21-Linux I2C 驱动实验”路径下。 我们可以先来体验一下,在 Linux 上操作 I2C 是多么的容易,我们可以先来看一下系统里面都有哪些 I2C的节点,这里以终结者 imx6ull 开发板为例。如下图所示: Linux 有一个非常重要的概念叫一切皆文件,那么我们能不能在应用层通过 open 这些节点来操作 I2C 来跟外设 I2C 通信的芯片进行一个数据交流呢?当然是可以的,我们来一起看一下,这里我们以 7 寸 RGB 屏幕上的触摸芯片 FT5X06 为例,迅为所有开发板都是支持迅为 7 寸 RGB 屏幕屏的,所有都是可以进
[单片机]
迅为imx6ull开发板<font color='red'>Linux</font> I2C<font color='red'>驱动</font>实验-应用程序与I2C通信
迅为IMX6ULL开发板Linux驱动初探-最简单的设备驱动-helloworld
经过前面的学习,我们了解了驱动开发的框架,本章节将带领大家实验操作,写最简单的驱动-helloworld。 Linux 设备驱动会以内核模块的形式出现,因为 linux 内核的整体架构就非常庞大,包含的组件也非常多,如果把所有的功能都编译到 linux 内核中会使得内核非常臃肿,为了解决这个问题,更方便地新增和删除功能,linux 提供了这样的机制,这种机制被称为模块。为了大家对模块有一个感性的认识,我们先来看一个最简单的驱动-helloworld。 驱动分为四个部分:  头文件  驱动模块的入口函数和出口函数  声明信息  功能实现 我们在 windows 上面新建一个 helloworld.c 文件,这里使用 sour
[单片机]
迅为IMX6ULL开发板<font color='red'>Linux</font><font color='red'>驱动</font>初探-最简单的设备<font color='red'>驱动</font>-helloworld
iMX6ULL终结者Linux WIFI驱动实验rtl8723 Wifi联网测试
在迅为i.MX6UL终结者开发板上使用的是usb接口的RTL8723 wifi模块,原理图如图 1所示: 可以看到RTL8723模块的接口非常简单,只有DP1和DM1连接到usb HUB芯片上,就可以完成通信电路。RTL8723是realtek公司的wifi芯片,已经提供了wifi驱动源码,就不需要我们自己去编写了,只需要将提供的wifi驱动源码添加到Linux内核中进行编译就可以了。 1.1 在Linux内核中添加wifi驱动 首先获取wifi驱动源码,放到Linux内核drivers/net/wireless目录下,如图 1.1.1所示: rtl8723BU目录下内容如图 1.1.2所示: 其中Kconfig文件是rtl
[单片机]
iMX6ULL终结者<font color='red'>Linux</font> WIFI<font color='red'>驱动</font>实验rtl8723 Wifi联网测试
linux驱动开发(十)——misc杂散设备
1:什么是misc驱动模型? 2:为什么要有misc驱动模型? 3:misc驱动模型的代码实现 4:misc驱动模型实战 参考: http://blog.csdn.net/yicao821/article/details/6785738 http://www.thinksaas.cn/topics/0/507/507168.html http://www.cnblogs.com/fellow1988/p/6235080.html https://www.zhihu.com/question/21508904 http://www.cnblogs.com/snake-hand/p/3212483.html http://blog.c
[单片机]
Linux下GPIO驱动(四) ----gpio_request();gpio_free();
//gpio_request申请gpio口 int gpio_request(unsigned gpio, const char *label) { struct gpio_desc *desc; struct gpio_chip *chip; int status = -EINVAL; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); // gpio_lock是自旋锁,上锁,保存FLAG在flags变量 if (!gpio_is_valid(gpio)) goto done; desc = &gpi
[单片机]
Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈。。。但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决方法,但是我还是没看懂,只能慢慢找,,, 我在insmod字符设备是,出现了一下提示信息 这里只列出主要部分: Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = c0004000 *pgd=00000000 Internal error: Oops: 7 Modules lin
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved