iis服务器助手广告
返回顶部
首页 > 资讯 > 操作系统 >linux驱动-gpio
  • 727
分享到

linux驱动-gpio

linux运维服务器 2023-09-01 19:09:24 727人浏览 安东尼
摘要

最近处理es8336声卡问题,最后排查是spk_ctl_gpio和hp_det_gpio这两个gpio导致的,所以恶补了一下gpio相关的知识,现在总结一下。 源代码使用的是飞腾的gitee上开源的内

最近处理es8336声卡问题,最后排查是spk_ctl_gpio和hp_det_gpio这两个gpio导致的,所以恶补了一下gpio相关的知识,现在总结一下。
源代码使用的是飞腾的gitee上开源的内核:https://gitee.com/phytium_embedded/phytium-linux-kernel.git

1. 概述

在这里插入图片描述

  1. 设备驱动层:定义了与硬件无关的GPIO api,包括GPIO的注册、卸载和控制等功能,而实现了某个模块的具体实现,比如led灯、按键等等。

  2. gpiolib抽象层:GPIO框架中的核心抽象层,它的作用是为设备驱动层和控制器层提供一致的接口,该层提供了包括上层设备驱动和下层控制器驱动的API接口。

  3. 控制器层:GPIO控制器的实现和管理,在该层中实现特定GPIO控制器的底层硬件操作和功能实现包括GPIO控制器的初始化、操作和管理等。负责GPIO寄存器的读写操作和GPIO中断的处理等。

其中gpiolib抽象层是GPIO框架中的核心层,也是linux内核自己实现的,一般情况下没有人会修改这部分的代码,控制器层一般是芯片厂家BSP工程师实现的,设备驱动层是驱动工程师根据开发版的实际情况实现的。优秀的BSP工程师和驱动工程师可以把驱动写得与硬件解耦,把硬件的信息填充到设备树中,驱动读取设备树的信息进行各种操作。

2. 控制器

这里以飞腾e2000为例子看看gpio控制器的驱动是怎么样的,在文件drivers/gpio/gpio-phytium-platfORM.c中,但是gpio的操作函数写在drivers/gpio/gpio-phytium-core.c和drivers/gpio/gpio-phytium-core.h中。

2.1 设备树

gpio0: gpio@28034000 {compatible = "phytium,gpio";reg = <0x0 0x28034000 0x0 0x1000>;interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;gpio-controller;#gpio-cells = <2>;#address-cells = <1>;#size-cells = <0>;porta {compatible = "phytium,gpio-port";reg = <0>;ngpiOS = <16>;};};gpio3: gpio@28037000 {compatible = "phytium,gpio";reg = <0x0 0x28037000 0x0 0x1000>;interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;gpio-controller;#gpio-cells = <2>;#address-cells = <1>;#size-cells = <0>;status = "disabled";porta {compatible = "phytium,gpio-port";reg = <0>;ngpios = <16>;};};

这里是gpio0和gpio3这个两个gpio模块,其实e2000有0到5,一共6个gpio模块,每个模块都有16个gpio,其中gpio0-2每个gpio都有一个硬件中断号,而gpio3-5则是这个组共享一个硬件中断号。当然,我看其他arm64的gpio都有复用功能,所以gpio的设备树写在pinctrl里面,现在e2000的gpio没有复用到其他模块,所以没有使用pinctrl。

2.2 驱动的数据结构

以我多年的驱动经验来看,所有的gpio控制器驱动做的事情不外乎以下几种:

  1. 分配私有数据结构体,这个结构体会包含struct gpio_chip结构体
  2. 读取设备树信息,填充gpio_chip结构体
  3. 把gpio_chip结构体绑定到平台设备中

实际上gpio的驱动跟中断和pinctrl放在一起的,初始化的时候会把irq_chip和 struct pinctrl_desc 和pinctrl_dev 一起填充的,这里主要讲解gpio,就不多扩展了。我们先看struct gpio_chip结构体:

struct gpio_chip {const char*label;//gpio控制器的名字struct gpio_device*gpiodev;//gpio设备描述符struct device*parent;//gpio的父设备struct module*owner;//下面是一系列的操作函数int (*get_direction)(struct gpio_chip *GC,unsigned int offset);int (*direction_input)(struct gpio_chip *gc,unsigned int offset);int  (*direction_output)(struct gpio_chip *gc,unsigned int offset, int value);int (*get)(struct gpio_chip *gc,unsigned int offset);void (*set)(struct gpio_chip *gc,unsigned int offset, int value);intbase;//gpio引脚基值u16ngpio;//gpio引脚个数const char*const *names;//每一个引脚的名字boolcan_sleep;//控制器是否能睡眠void __iomem *reg_dat;//gpio数据寄存器基地址void __iomem *reg_set;//gpio设置寄存器基地址void __iomem *reg_clr;//gpio控制寄存器基地址void __iomem *reg_dir_out;//gpio输出寄存器基地址void __iomem *reg_dir_in;//gpio输入寄存器基地址};

gpio_chip结构体中包含了对应GPIO端口的硬件基地址、引脚数、GPIO组数、GPIO编号和IRQ号等重要信息。同时,它还包括了访问GPIO寄存器的函数指针,例如读取和写入寄存器等函数,以及描述GPIO的信息和配置的特定标志。其中最重要的是struct gpio_device *gpiodev; 他表示gpio设备描述符。这个结构体存放着gpio控制器的设备信息和每个引脚的描述符结构体,我们来看看struct gpio_device结构体:

struct gpio_device {intid;//表示这是系统中第几个GPIO控制器struct devicedev;struct cdevchrdev;struct device*mockdev;struct module*owner;struct gpio_chip*chip;//gpio管理硬件的结构体,记录寄存器信息及其操作函数struct gpio_desc*descs;//引脚的描述符指针,每一个引脚对应一个gpio_desc结构体intbase;//gpio号码基值u16ngpio;//gpio个数const char*label;//gpio控制器的名字void*data;struct list_head        list;struct blocking_notifier_head notifier;};

gpio_device结构体中包含了与GPIO设备(GPIO控制器)相关的重要信息,例如GPIO控制器ID、GPIO号、GPIO个数、GPIO管理硬件的结构体和gpio引脚描述符结构体。最重要的是GPIO管理硬件的结构体gpio_chip 就是刚刚第一个介绍的数据结构,gpio设备是通过gpio_chip 找到对用的硬件信息和操作方法的;其次是gpio_desc结构体,每一个引脚对应一个gpio_desc结构体,他们通过数组的形式排列,我们看看gpio_desc结构体:

struct gpio_desc {struct gpio_device*gdev;//属于哪个GPIO控制器unsigned longflags;//gpio引脚属性,比如是否被使用、是否开漏等等const char*label;const char*name;//引脚名字#ifdef CONFIG_OF_DYNAMICstruct device_node*hog;#endif#ifdef CONFIG_GPIO_CDEVunsigned intdebounce_period_us;#endif};

gpio_desc结构体主要记录GPIO引脚的硬件信息和状态信息。

在这里插入图片描述
这3个结构体的关系如上图所示,以上这3个结构体就包含了gpio控制器的硬件信息、状态信息和操作方法集合,这就我们的设备驱动提供了底层的基础,我们的驱动就是通过gpiolib抽象层提供的API调用到这个操作方法的。

3. 设备驱动

在控制器驱动准备好的情况下,我们使用gpio是一件很简单的事情,就拿es8336这个网卡驱动举个例子,先看设备树:

mio14: i2c@28030000 {...codec0:es8336@10 {det-gpios = <&gpio2 5 0>;sel-gpios = <&gpio2 6 0>;...   };};

其中gpio的设备树就两行,其他不重要的就忽略了。
驱动文件在sound/soc/codecs/es8336.c:

es8336->spk_ctl_gpio = devm_gpiod_get_index_optional(&i2c->dev, "sel", 0,GPIOD_OUT_HIGH);ret = of_property_read_u8(i2c->dev.of_node, "mic-src", &es8336->mic_src);if (ret != 0) {dev_dbg(&i2c->dev, "mic1-src return %d", ret);es8336->mic_src = 0x20;}dev_dbg(&i2c->dev, "mic1-src %x", es8336->mic_src);if (!es8336->spk_ctl_gpio)dev_info(&i2c->dev, "Can not get spk_ctl_gpio\n");elsees8336_enable_spk(es8336, false);es8336->hp_det_gpio = devm_gpiod_get_index_optional(&i2c->dev, "det", 0,GPIOD_IN);if (!es8336->hp_det_gpio) {dev_info(&i2c->dev, "Can not get hp_det_gpio\n");} else {INIT_DELAYED_WORK(&es8336->work, hp_work);hp_irq = gpiod_to_irq(es8336->hp_det_gpio);ret = devm_request_threaded_irq(&i2c->dev, hp_irq, NULL,es8336_irq_handler,IRQF_TRIGGER_FALLING |IRQF_TRIGGER_RISING |IRQF_ONESHOT,"es8336_interrupt", es8336);if (ret < 0) {dev_err(&i2c->dev, "request_irq failed: %d\n", ret);return ret;}}

其实设备驱动都是使用gpiolib提供的API:

  1. gpiod_get_indexed:通过索引号获取GPIO设备引脚。
  2. gpiod_get_optional:尝试获取GPIO设备引脚,如果失败返回NULL,不会导致注册失败。
  3. gpiod_get_optional_indexed:与gpiod_get_optional类似,但通过索引号获取GPIO设备引脚。
  4. gpiod_get_raw:通过GPIO编号获取GPIO设备引脚,不进行方向和值的配置。
  5. devm_gpiod_get:这个函数自动为一个特定的设备申请所需的GPIO,不需要手动释放,适合临时使用的GPIO资源。
  6. devm_gpiod_get_index:这个函数允许为使用多个GPIO的设备申请多个GPIO引脚,返回一个struct gpiod_hanlde数组。
  7. devm_gpiod_get_optional:如果存在,允许驱动程序获取所需的GPIO,而不会阻止设备与其余的GPIO资源一起初始化。
  8. devm_gpiod_get_optional_index:类似于devm_gpiod_get_optional,支持索引GPIO。
  9. gpio_request:向内核申请一个GPIO引脚。
  10. gpio_free:释放一个已经使用的GPIO引脚。
  11. gpio_direction_input:配置GPIO引脚为输入模式。
  12. gpio_direction_output:配置GPIO引脚为输出模式。
  13. gpio_get_value:读取GPIO引脚状态。如果 GPIO 引脚已配置为输出模式,则返回当前输出值。如果 GPIO 引脚未配置或配置为输入模式,则返回实际引脚上的输入值。
  14. gpio_set_value:设置GPIO引脚状态为高或低电平。如果 GPIO 引脚已配置为输出模式,则设置GPIO引脚状态为用户指定电平;如果 GPIO 引脚是输入模式,此函数没有作用。
  15. gpio_to_irq:将 GPIO 引脚转换为专用中断号。
  16. gpio_request_one:请求单个GPIO。
  17. gpio_free_array:释放一组由gpio_request_array()调用请求的GPIO。
  18. gpio_direction_input_array:将一组GPIO方向设置为输入模式。
  19. gpio_direction_output_array:将一组GPIO方向设置为输出模式。
  20. gpio_get_array:将一组GPIO值读入缓冲区中。
  21. gpio_set_array:将一组GPIO指定的值写入用户指定的缓冲区中。
  22. gpio_get_value_cansleep:读取GPIO引脚状态,如果引脚已配置为输出模式,则将与其关联的电平值复制到调用函数的参数变量中,如果引脚已配置为输入模式,则等待GPIO中断或超时发生后将其值复制到调用函数的参数变量中。
  23. gpio_set_value_cansleep:设置GPIO端口电平,如果引脚仍被配置为输入模式,则什么也不做。

来源地址:https://blog.csdn.net/sinat_22338935/article/details/130608535

--结束END--

本文标题: linux驱动-gpio

本文链接: https://www.lsjlt.com/news/389393.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • linux驱动-gpio
    最近处理es8336声卡问题,最后排查是spk_ctl_gpio和hp_det_gpio这两个gpio导致的,所以恶补了一下gpio相关的知识,现在总结一下。 源代码使用的是飞腾的gitee上开源的内...
    99+
    2023-09-01
    linux 运维 服务器
  • 如何让Linux驱动11-Linux设备驱动统一模型
    这期内容当中小编将会给大家带来有关如何让Linux驱动11-Linux设备驱动统一模型,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1. 设备树概念1.1.设备树感性认识设备树(Device Tree),...
    99+
    2023-06-15
  • Linux 网络驱动-MAC、PHY层驱动框架(三)
    I.MX6ULL 网络外设设备树    I.MX6ULL 有两个 10/100M 的网络 MAC 外设,因此 I.MX6ULL 网络驱动主要就是这两个网络 MAC 外设的驱动。这两个外设的驱动都是一样的,我们分析其 中一个就行了,首先肯定是...
    99+
    2023-09-02
    linux 运维 服务器
  • Linux系统如何使用gpio接口
    这篇文章主要为大家展示了“Linux系统如何使用gpio接口”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Linux系统如何使用gpio接口”这篇文章吧。GPIO 资源是相对来说较为简单,而且比...
    99+
    2023-06-28
  • linux串口驱动详解
    Linux串口驱动是用于控制和管理串口设备的软件模块。它提供了一组函数和数据结构,使得应用程序可以通过操作这些函数和数据结构来与串口...
    99+
    2023-09-13
    linux
  • Linux怎么加载raid驱动
    这篇文章主要介绍“Linux怎么加载raid驱动”,在日常操作中,相信很多人在Linux怎么加载raid驱动问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux怎么加载raid驱动”的疑惑有所帮助!接下来...
    99+
    2023-06-13
  • Linux红外驱动是什么
    这篇文章主要讲解了“Linux红外驱动是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux红外驱动是什么”吧!红外遥控是我们经常见到的一种无线收发设备,比如电视遥控,空调遥控,现在...
    99+
    2023-06-15
  • linux卸載驱动的方法
    在Linux中卸载驱动的方法取决于驱动是如何安装的。以下是一些常见的方法:1. 在命令行中使用"modprobe"命令卸载驱动。例如...
    99+
    2023-09-13
    linux
  • Linux如何编译声卡驱动
    Linux如何编译声卡驱动,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。关于Linux编译声卡驱动:惠普笔记本刚买来时,安装Debian 5,通常会遇到两个问题。一个是无线...
    99+
    2023-06-16
  • Linux如何安装显卡驱动
    小编给大家分享一下Linux如何安装显卡驱动,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Linux安装显卡驱动五部曲:***步:下载一个for Linux版的显...
    99+
    2023-06-17
  • linux如何查看串口驱动
    在Linux中,可以使用以下命令来查看串口驱动:1. 使用`dmesg | grep tty`命令来查看系统启动时检测到的串口设备信...
    99+
    2023-09-06
    linux
  • 如何安装Linux网卡驱动
    小编给大家分享一下如何安装Linux网卡驱动,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!Linux下网卡驱动安装及问题:首先需要确认网卡是否安装。PCI详细信息查看#lspci\\如果有Ethernet相关信息说明网卡硬...
    99+
    2023-06-16
  • Linux驱动开发怎么学习
    这篇文章主要讲解了“Linux驱动开发怎么学习”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux驱动开发怎么学习”吧! 学会写简单的makefile 编一应用程序,可以用makefil...
    99+
    2023-06-16
  • 如何解析Linux 驱动架构
    今天就跟大家聊聊有关如何解析Linux 驱动架构,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。首先,需要熟悉操作系统的设计与实现,推荐大家看 MINIX作者的那部书,同时把MINIX...
    99+
    2023-06-28
  • Linux下如何进行SPI驱动
    Linux下如何进行SPI驱动,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. SPI总线1.1. SPI总线概述SPI,是英语Serial Peripheral &nb...
    99+
    2023-06-15
  • linux系统如何更新驱动
    在Linux系统中,可以通过以下步骤更新驱动:1. 打开终端,使用管理员权限登录。2. 使用命令`sudo apt update`更...
    99+
    2023-09-06
    linux
  • Linux内核驱动开发的EXPORT_SYMBOL
    EXPORT_SYMBOL是Linux内核中的一个宏,用于将一个符号(函数、变量等)导出给其他模块使用。在Linux内核中,有一些符...
    99+
    2023-09-28
    Linux
  • linux怎么编译驱动程序
    编译Linux驱动程序通常需要以下步骤: 下载并安装适当的Linux内核源代码。您可以从Linux官方网站上下载所需的内核源代码...
    99+
    2024-03-06
    linux
  • 全志T3 Linux显示驱动分析
    1、总体架构         全志T3处理器的显示框架是基于标准Linux的帧缓冲架构,其结构如图 1.1所示。显示控制器DE的驱动架构如图 1.2所示,包括屏蔽差异的显示管理抽象层,以及显示图层驱动、显示设备驱动、背光驱动、enhance...
    99+
    2023-01-31
    显示驱动 Linux
  • Linux下怎么升级网卡驱动
    这篇文章主要讲解了“Linux下怎么升级网卡驱动”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux下怎么升级网卡驱动”吧!更新linux下的网卡驱动。检查网卡版本Ifconfig -a...
    99+
    2023-06-28
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作