知识整理–linux内核的gpiolib学习
gpiolib引入:(1)一个事实:很多硬件都要用到GPIO,GPIO会复用;(2)如果同一个GPIO被2个驱动同时控制了,就会出现bug;(3)内核提供gpiolib来统一管理系统中所有GPIO;(4)gpiolib本身属于驱动框架的一部分
和动态映射静态映射读写寄存器比较起来
gpiolib学习重点:
- gpiolib的建立过程:和虚拟地址的建立类似,内核在启动的过程中去调用gpiolib建立函数建立gpiolib
- gpiolib的使用方法:申请、使用、释放
- gpiolib的架构:涉及哪些目录的哪些文件里面的哪些函数哪些数据结构哪些变量,谁调用谁,为什么要分开为什么不写在一个文件,等能理解这些的时候就有了架构意识。继续努力!
开机调用gpiolib的建立函数
gpiolib的建立函数:
s5pv210_gpiolib_init
gpiolib的建立
填充一个个
s3c_gpio_chip
这个结构体定义的变量(GPIO端口的抽象),最后把一个个端口的抽象的地址挂接到内核维护的一个gpio_desc结构体指针数组
s3c_gpio_chip结构体
(1)这个结构体是一个GPIO端口的抽象,这个结构体的一个变量就可以完全的描述一个端口。
(2)端口和IO口是两个概念。S5PV210有很多个IO口(160个左右),这些IO口被分成N个端口(port),每个端口包含了M个IO口。(M个IO口又被映射到一个一个的寄存器).(有时候一个端口就只有一个寄存器代表有时候也有多个)。譬如GPA0是一个端口组,里面包含了8个IO口,我们一般记作:GPA0_0(或GPA0.0)、GPA0_1…
这是芯片设计决定的
(3)内核中为每个GPIO分配了一个编号,编号是一个数字(譬如一共有160个IO时编号就可以从1到160连续分布),编号可以让程序很方便的去识别每一个GPIO。
附:
arch/arm/plat-samsung/include/plat/gpio-core.h:struct s3c_gpio_chip
include/asm-generic/gpio.h:struct gpio_chip
arch/arm/plat-samsung/include/plat/gpio-cfg.h:struct s3c_gpio_cfg
s5pv210_gpio_4bit结构体数组
(1)这个东西是一个结构体数组,数组中包含了很多个struct s3c_gpio_chip
类型的变量。一个struct s3c_gpio_chip
类型的变量就代表了一个端口
(2)S5PV210_GPA0宏:设置当前端口的基础编号(读者自行追踪,慢慢体会),区别s3c_gpio_chip
里的base
附:S5PV210_GPA0宏
函数samsung_gpiolib_add_4bit_chips
具体进行gpiolib的注册的。这个函数接收的参数是当前文件中定义好的结构体数组s5pv210_gpio_4bit
(2个参数分别是数组名和数组元素个数),这个数组中其实就包含了当前系统中所有的IO端口的信息(这些信息包含:端口的名字、端口中所有GPIO的编号、端口操作寄存器组的虚拟地址基地址、端口中IO口的数量、端口上下拉等模式的配置函数、端口中的IO口换算其对应的中断号的函数等,有一些当前还没被赋值,接下来会被填充好)
samsung_gpiolib_add_4bit_chips
├── samsung_gpiolib_add_4bit 填充每一个GPIO被设置成输入模式/输出模式的操作方法
└── s3c_gpiolib_add 检测并完善chip的direction_input/direction_ouput/set/get这4个方法
│
└── gpiochip_add 真正向内核注册gpiolib的函数
这个注册就是将我们的封装了一个GPIO端口的所有信息的chip结构体变量挂接到
内核gpiolib模块定义的一个gpio_desc数组中的某一个格子中
(和前面两个不一样,这个不是三星工程师写的,这个是内核开发者写的;
驱动就是内核开发者写一部分,厂商驱动开发工程师写一部分)
arch/arm/plat-samsung/gpiolib.c:samsung_gpiolib_add_4bit
arch/arm/plat-samsung/gpio.c:s3c_gpiolib_add
drivers/gpio/gpiolib.c:gpiochip_add
(1)哪个目录的哪个文件
(2)函数名中为什么有个4bit:三星的CPU中2440的CON寄存器是2bit对应一个IO口,而6410和210以及之后的系列中CON寄存器是4bit对应1个IO口。所以gpiolib在操作2440和210的CON寄存器时是不同的
整体框架
到这里停下来看看,到这里gpiolib的建立已经分析完了。不考虑数据结构s3c_gpio_chip等这些东西定义对应的目录,整体观望分析的目录和文件结构
从驱动框架角度分析gpiolib
之前的分析已经告一段落,目前已经搞清楚了gpiolib的建立工程。但是这只是整个gpiolib建立的一部分,是厂商驱动工程师负责的那一部分;还有另一部分是内核开发者提供的驱动框架的那一部分,就是接下来要去分析的第2部分
drivers/gpio/gpiolib.c这个文件中所有的函数构成了第2部分,也就是内核开发者写的gpiolib框架部分
drivers/gpio/gpiolib.c概览
drivers/gpio/gpiolib.c这个文件中提供的函数主要有以下部分:
gpiochip_add: 是框架开出来的接口,给厂商驱动工程师用,用于向内核注册我们的gpiolib
gpio_request: 是框架开出来的接口,给使用gpiolib来编写自己的驱动的驱动工程师用的,
驱动中要想使用某一个gpio,就必须先调用gpio_request接口来向内核的gpiolib申请资源,得到允许后才可以去使用这个gpio
gpio_free: 对应gpio_request,用来释放申请后用完了的gpio
gpio_request_one/gpio_request_array: 这两个是gpio_request的变种
gpiochip_is_requested: 接口用来判断某一个gpio是否已经被申请了
gpio_set_value设置输出值 gpio_get_value获取IO口值
gpio_direction_input/gpio_direction_output: 接口用来设置GPIO为输入/输出模式
以上的接口属于一类,这些都是给写其他驱动并且用到了gpiolib的人使用的
剩下的还有另外一类函数,是gpiolib内部自己的一些功能实现的代码
gpio_direction_input/gpio_direction_output:
gpiolib的attribute部分
和之前文章提到的LED驱动框架相比较,分析gpiolib的建立过程,整个过程其实就是在填充一个结构体变量,然后绑定到一个description数组。但是还有一个问题就是
/sys/class/gpio
这个文件是怎么来的,/sys/class/gpio
底下的那些设备文件又是怎么来的,之前的led驱动是通过class_create
、device_create
来创建设备文件。所以可以推测gpiolib也是用这两个函数
gpiolib驱动也是用模块的机制实现的,从下往上分析:
DEVICE_ATTR相关知识:点击这里
使用gpiolib完成led驱动
第1步:使用gpio_request申请要使用的一个GPIO
第2步:gpio_direction_input/gpio_direction_output 设置输入/输出模式
第3步:设置输出值—gpio_set_value;获取IO口值—gpio_get_value
示例程序:leds-s5pv210.c 图中高亮部分为新添加 ;源代码
上述程序只是在led1上编写代码测试,扩展支持led2和led3、led4.可以分开注册也可以使用gpio_request_array去一次性注册
学习linux中查看gpio使用情况的方法:
内核中提供了虚拟文件系统debugfs,里面有一个gpio文件,提供了gpio的使用信息。
使用方法:mount -t debugfs debugfs /tmp,然后cat /tmp/gpio即可得到gpio的所有信息,使用完后umount /tmp卸载掉debugfs