linux设备驱动 gpio,在Linux驱动中使用gpio子系统

reference:

内核相关文档

Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt

Documentation\gpio\gpio.txt

Documentation\devicetree\bindings\gpio\gpio.txt

背景

随着内核的发展,linux驱动框架在不断的变化。在早期,GPIO子系统存在之前,我们驱动需要在代码中配置寄存器来使用GPIO引脚。

此后,出现了gpio子系统,后来又出现了pinctrl子系统。

有些平台的实现没有使用内核提供的pinctrl子系统,而是继续采用在内核提供pinctrl子系统前自己实现的那套机制来pinmux操作,如Ti的omap平台;

有些平台则基于pinctrl子系统来实现pinmux、pinconf的控制。

介绍

GPIO子系统可以说是Linux中最简单的子系统。

GPIO(General Purpose Input Output):负责管理整个系统各gpio输入输出管脚的使用情况,同时通过sys文件系统导出了调试信息和应用层控制接口。

Pinctrl(Pin Control):负责管理SOC中各pin的状态,比如输出电流能力、是否有内部上拉或者下拉,是否有功能复用等参数。

要想操作GPIO引脚,需要先把所用引脚配置成GPIO功能,这个通过pinctrl子系统来实现。然后可以根据设置的引脚的方向来读取引脚的值和设置输出值。

在BSP工程师实现好GPIO子系统后,我们就可以在设备树中指定GPIO引脚,在驱动中使用GPIO子系统的标准函数来获取GPIO、设置GPIO方向、读取/设置GPIO的值。这样的驱动代码是于单板无关的。

gpio子系统

gpio子系统内部实现主要提供了两类接口:

一类给bsp工程师,用于注册gpio chip(也就是所谓的gpio控制器驱动)

另一部分给驱动工程师使用,为驱动工程师屏蔽了不同gpio chip之间的区别,驱动工程师调用的api的最终操作流程会导向gpio对应的gpio chip的控制代码,也就是bsp的代码。

核心实现

gpio子系统的实现源码在drivers/gpio文件夹下,主要文件有:

在安卓系统中,实现源码在kernel/drivers/gpio

文件

作用

devres.c

针对gpio api增加的devres机制的支持

gpiolib.c

gpio子系统的核心实现

gpiolib-of.c

对设备树的支持

gpiolib-acpi.c

和acpi相关,不分析

gpio-xxx.c

根据平台的不同,所对应的gpio控制

gpio子系统提供了两层接口,一层给上层驱动工程师调用,一层给下层bsp工程师调用。

上层使用前,当然先得bsp工程师完成对应的动作。

Linux内核中GPIO子系统的软件驱动分层图

GPIO子系统有两套接口:

一是基于描述符(descriptor-based)的,相关api函数都是以"gpiod_"为前缀,它使用gpio_desc结构来表示一个引脚。

另一种是老(legency)的,相关api函数都是以"gpio_"为前缀,它使用一个整数来表示一个引脚,强烈建议不要使用legacy的接口函数。

其实,legacy gpio大部分api就是基于描述符api来实现的,我们可以看到很多legacy api内部的实现调用了to_desc。

// 1.获取GPIO

gpiod_get;

gpiod_get_index;

gpiod_get_array;

devm_gpiod_get;

devm_gpiod_get_index;

devm_gpiod_get_array;

// 2.设置方向

gpiod_direction_input;

gpiod_direction_output;

// 3.读值、写值

gpiod_get_value;

gpiod_set_value;

// 4\. 设为中断(如果必要)

request_irq(gpiod_to_irq(gpio_desc)...); //将gpio转为对应的irq,然后注册该irq的中断handler

// 5.释放GPIO

gpiod_put;

gpiod_put_array;

devm_gpiod_put;

devm_gpiod_put_array;

前缀为"devm_"的含义是设备资源管理,这是一种自动释放资源的机制。

思想:“资源是属于设备的,设备不存在时资源就可以自动释放”。

背景:在Linux驱动开发过程中,先申请了GPIO,再申请内存,如果内存申请失败,那么在返回之前就需要先释放GPIO资源。如果使用的是devm相关函数,在内存申请失败时可以直接返回,设备的销毁函数会自动地释放已经申请了的GPIO资源。

因此,建议使用devm相关函数操作GPIO。

gpio控制api( descriptor)

使用基于描述符的接口时,GPIO被作为一个描述符来使用。

#include

// 更多相关的说明可以参考 Documentation/gpio/consumer.txt

获取一个或一组GPIO

struct gpio_desc * gpiod_get(struct device *dev,

const char *con_id,

enum gpiod_flags flags);

/*

在允许GPIO不存在时,可以使用gpiod_get_optional()和gpiod_get_index_optional()函数。

这两个函数在没有成功分配到GPIO的时候返回NULL而不是-ENOENT。

*/

struct gpio_desc * gpiod_get_optional(struct device *dev,

const char *con_id,

enum gpiod_flags flags);

struct gpio_descs {

unsigned int ndescs; // 数量

struct gpio_desc *desc[]; // 每一个 desc 的情况

}

// 返回gpio_descs 注意:不是 gpio_desc

struct gpio_descs * gpiod_get_array(struct device *dev,

const char *con_id,

enum gpiod_flags flags);

/*多个Pin时需要附带index参数。*/

struct gpio_desc * gpiod_get_index(struct device *dev,

const char *con_id,

unsigned int idx,

enum gpiod_flags flags);

struct gpio_desc * gpiod_get_index_optional(struct device *dev,

const char *con_id,

unsigned int index,

enum gpiod_flags flags);

struct gpio_desc * devm_gpiod_get(struct device *dev, const char *con_id,

enum gpiod_flags flags);

struct gpio_desc * devm_gpiod_get_index(struct device *dev,

const char *con_id,

unsigned int idx,

enum gpiod_flags flags);

描述:必须通过调用gpiod_get()函数族来获取对应的描述符。

参数解析:

con_id:字符串类型,即GPIO的名字;

一般需要查看设备树中的定义。除此之外,我们还可以在设备树文件里添加参数(GPIO_ACTIVE_LOW、GPIO_OPEN_DRAIN、GPIO_OPEN_SOURCE)来触发该接口内部设置gpio,具体的参数格式和具体的gpio chip driver有关,一般可以在Documentation/devicetree/bindings/gpio里找到对应平台的方法。

有关DeviceTree情况中con_id参数的更详细说明请参阅Documentation/gpio/board.txt

例如:

在SD卡驱动看到的去查找名字为cd-gpios的gpio:

// simple.c:

ctx->cd_gpio = devm_gpiod_get_optional(dev, "cd", 0);

在使用SD卡驱动的主dts就有cd pin的定义:

// xxx.dts:

cd-gpios = ;

index:逻辑下标。将一个GPIO设备(DESC)下的多个Pin看成一个数组,此时index是数组成员下标。

内核文档有个例子,比如gpio如下定义:

led-gpios = , /* red */

, /* green */

; /* blue */

如果index是0,那么对应的就是gpio 15;如果index是1,那么对应就是gpio 16,以此类推。

flags:用于可选地指定GPIO的方向和初始值,它的值可以是:

GPIOD_ASIS或0表示根本不初始化GPIO。需要随后使用专门的函数设置方向

GPIOD_IN初始化GPIO作为输入。

GPIOD_OUT_LOW将GPIO初始化为输出,值为0。

GPIOD_OUT_HIGH将GPIO初始化为输出,值为1。

GPIOD_OUT_LOW_OPEN_DRAIN:与GPIOD_OUT_LOW相同,但强制以开漏的方式使用

GPIOD_OUT_HIGH_OPEN_DRAIN:与GPIOD_OUT_HIGH相同,但强制以开漏的方式使用

最后两个标志用于必须开漏方式的情况,比如GPIO被用作I2C时,如果该GPIO尚未在映射(参见board.txt)中被配置为开漏方式,将被强制配置为开漏方式并给出WARNING。

这两个函数都返回有效的GPIO描述符或可被IS_ERR()检查的错误代码(它们永远不会返回NULL指针)。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值