linux内核的gpiolib

gpiolib引入
(1)一个事实:很多硬件都要用到GPIO、GPIO会复用
(2)如果同一个GPIO被2个驱动同时控制了,就会出现bug
(3)内核提供gpiolib来统一管理系统中所有GPIO
(4)gpiolib本身属于驱动框架的一部分


gpiolib学习重点
(1)gpiolib的建立过程
(2)gpiolib的使用方法:申请、使用、释放
(3)gpiolib的架构:涉及哪些目录的哪些文件


1.gpiolib的建立
smdkc110_map_io (arch/arm/mach-s5pv210/mach-smdkc110.c)
s5pv210_gpiolib_init 这个函数就是我们gpiolib初始化的函数,在 (arch/arm/mach-s5pv210/gpiolib.c)中。

s5pv210_gpiolib_init函数分析:
__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;

}
**一个非常重要的结构体:

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
};
struct s3c_gpio_chip,这个结构体是一个GPIO端口的抽象,这个结构体的一个变量就可以完全的描述一个IO端口。
注意:IO口和IO端口的区别?
我们S5PV210有407个左右的IO口,这些IO口首先被划分为M个IO端口,每一个IO端口又有N个IO口。所有我们总共是 M * N =407.
GPIOA、GPIOB、GPIOC等等就叫一个个的IO端口。
GPIOA_0、GPIOA_1、GPIOA_2这就是GPIOA端口里面的0 1 2三个GPIO口。

端口和IO口是两个概念。S5PV210有很多个IO口(407个左右),这些IO口首先被分成N个端口(port group),然后每个端口中又包含了M个IO口。譬如GPA0是一个端口,里面包含了8个IO口,我们一般记作:GPA0_0(或GPA0.0)、GPA0_1、。

s3c_gpio_chip 结构体中的chip成员就是对一个端口信息的具体描述


如何得到GPIO的数量:s5pv210_gpio_4bit数组里面有描述50多个IO端口,每一个IO端口又有4-8个的IO口。所以s5pv210_gpio_4bit这个数组就是对所有的IO端口的描述。这个东西是一个结构体数组,数组中包含了很多个struct s3c_gpio_chip类型的变量。

#define S5PV210_GPIO_A0_NR (8)
#define S5PV210_GPIO_A1_NR (4)
#define S5PV210_GPIO_B_NR (8)
#define S5PV210_GPIO_C0_NR (5)
#define S5PV210_GPIO_C1_NR (5)
#define S5PV210_GPIO_D0_NR (4)
#define S5PV210_GPIO_D1_NR (6)
#define S5PV210_GPIO_E0_NR (8)
#define S5PV210_GPIO_E1_NR (5)
#define S5PV210_GPIO_F0_NR (8)
#define S5PV210_GPIO_F1_NR (8)
#define S5PV210_GPIO_F2_NR (8)
#define S5PV210_GPIO_F3_NR (6)
#define S5PV210_GPIO_G0_NR (7)
#define S5PV210_GPIO_G1_NR (7)
#define S5PV210_GPIO_G2_NR (7)
#define S5PV210_GPIO_G3_NR (7)
#define S5PV210_GPIO_H0_NR (8)
#define S5PV210_GPIO_H1_NR (8)
#define S5PV210_GPIO_H2_NR (8)
#define S5PV210_GPIO_H3_NR (8)
#define S5PV210_GPIO_I_NR (7)
#define S5PV210_GPIO_J0_NR (8)
#define S5PV210_GPIO_J1_NR (6)
#define S5PV210_GPIO_J2_NR (8)
#define S5PV210_GPIO_J3_NR (8)
#define S5PV210_GPIO_J4_NR (5)

#define S5PV210_GPIO_MP01_NR (8)
#define S5PV210_GPIO_MP02_NR (4)
#define S5PV210_GPIO_MP03_NR (8)
#define S5PV210_GPIO_MP04_NR (8)
#define S5PV210_GPIO_MP05_NR (8)
#define S5PV210_GPIO_MP06_NR (8)
#define S5PV210_GPIO_MP07_NR (8)

#define S5PV210_GPIO_MP10_NR (8)
#define S5PV210_GPIO_MP11_NR (8)
#define S5PV210_GPIO_MP12_NR (8)
#define S5PV210_GPIO_MP13_NR (8)
#define S5PV210_GPIO_MP14_NR (8)
#define S5PV210_GPIO_MP15_NR (8)
#define S5PV210_GPIO_MP16_NR (8)
#define S5PV210_GPIO_MP17_NR (8)
#define S5PV210_GPIO_MP18_NR (7)

#define S5PV210_GPIO_MP20_NR (8)
#define S5PV210_GPIO_MP21_NR (8)
#define S5PV210_GPIO_MP22_NR (8)
#define S5PV210_GPIO_MP23_NR (8)
#define S5PV210_GPIO_MP24_NR (8)
#define S5PV210_GPIO_MP25_NR (8)
#define S5PV210_GPIO_MP26_NR (8)
#define S5PV210_GPIO_MP27_NR (8)
#define S5PV210_GPIO_MP28_NR (7)

#define S5PV210_GPIO_ETC0_NR (6)
#define S5PV210_GPIO_ETC1_NR (8)
#define S5PV210_GPIO_ETC2_NR (8)
#define S5PV210_GPIO_ETC4_NR (6)


内核中为每个GPIO分配了一个编号,编号是一个数字(譬如一共有380个IO时编号就可以从1到407连续分布),编号可以让程序很方便的去识别每一个GPIO


S5PV210_GPA0(0)宏
#define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
S5PV210_GPIO_A0_START = 0,
所以我们分析:
S5PV210_GPA0的base是0。

我们分析一下S5PV210_GPA1(0):
S5PV210_GPA1(0):
调用:
#define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr))
调用:
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)
所以:
S5PV210_GPA1(0)的base值是9.

我们查看/sys/class/gpio里面的gpiochip0,它的base值刚好是:0。对应的是S5PV210_GPA0。
查看/sys/class/gpio里面的gpiochip9,它的base值刚好是:9.对应的是S5PV210_GPA1


总结一下:/sys/class/gpio/gpiochipx,每一个都是对应一个IO端口的,里面的base就是这个IO端口第一个IO口的编号。gpiochipx的x是和它的base值相同的。ngpio就是代表这个IO端口有多少个IO口。
所以,/sys/class/gpio/gpiochipx是由s5pv210_gpio_4bit这个数组来决定的。
S5PV210_GPA0宏的返回值就是GPA0端口的某一个IO口的编号值,传参就是我们这个IO口在GPA0端口中的局部编号。
例如:S5PV210_GPA0(0),返回的就是0,所以我们GPIOA_0的编码号就是0,传参是0说明这个IO在GPA0端口中的局部编号也是0.
再例如:S5PV210_GPA1(0),返回的就是9,所以我们GPA1_0的编码号就是9,传参是0说明这个IO在GPA1端口中的局部编号也是0.

samsung_gpiolib_add_4bit_chips这个函数才是具体进行gpiolib的注册的。这个函数接收的参数是我们当前文件中定义好的结构体数组s5pv210_gpio_4bit(其实2个参数分别是数组名和数组元素个数),这个数组中其实就包含了当前系统中所有的IO端口的信息(这些信息包含:端口的名字、端口中所有GPIO的编号、端口操作寄存器组的虚拟地址基地址、端口中IO口的数量、端口上下拉等模式的配置函数、端口中的IO口换算其对应的中断号的函数)。


samsung_gpiolib_add_4bit_chips函数:
在 arch/arm/plat-samsung/gpiolic.c:
函数名中为什么有个4bit:三星的CPU中2440的CON寄存器是2bit对应一个IO口,而6410和210以及之后的系列中CON寄存器是4bit对应1个IO口。所以gpiolib在操作2440和210的CON寄存器时是不同的

函数调用关系
samsung_gpiolib_add_4bit_chips
samsung_gpiolib_add_4bit
s3c_gpiolib_add
经过分析,发现samsung_gpiolib_add_4bit内部其实并没有做gpiolib的注册工作,而是还在做填充,填充的是每一个GPIO被设置成输入模式/输出模式的操作方法。

s3c_gpiolib_add
首先检测并完善chip的direction_input/direction_ouput/set/get这4个方法,然后调用gpiochip_add方法进行真正的注册操作。其实这个注册就是将我们的封装了一个GPIO端口的所有信息的chip结构体变量挂接到内核gpiolib模块定义的一个gpio_desc数组中的某一个格子中。
for (id = base; id < base + chip->ngpio; id++) {
gpio_desc[id].chip = chip;
这里的注册,每一个IO口都会对应一个chip,同一个IO端口里面的,chip是相同的。


内核开发者提供的驱动框架
之前的分析已经告一段落,截至目前我们已经搞清楚了gpiolib的建立工程。但是这只是整个gpiolib建立的一部分,是厂商驱动工程师负责的那一部分;还有另一部分是内核开发者提供的驱动框架的那一部分,就是我们后面要去分析的第2条主线。
drivers/gpio/gpiolib.c这个文件中所有的函数构成了我们第2部分,也就是内核开发者写的gpiolib框架部分。这个文件中提供的函数主要有以下部分:
1.gpiochip_add: 是框架开出来的接口,给厂商驱动工程师用,用于向内核注册我们的gpiolib
2.gpio_request: 是框架开出来的接口,给使用gpiolib来编写自己的驱动的驱动工程师用的,驱动中要想使用某一个gpio,就必须先调用gpio_request接口来向内核的gpiolib部分申请,得到允许后才可以去使用这个gpio。
3.gpio_free: 对应gpio_request,用来释放申请后用完了的gpio
4.gpio_request_one/gpio_request_array: 这两个是gpio_request的变种 gpiochip_is_requested: 接口用来判断某一个gpio是否已经被申请了gpio_direction_input/gpio_direction_output: 接口用来设置GPIO为输入/输出模式,注意该函数内部实际并没有对硬件进行操作,只是通过chip结构体变量的函数指针调用了将来SoC厂商的驱动工程师写的真正的操作硬件实现gpio设置成输出模式的那个函数。

以上的接口属于一类,这些都是给写其他驱动并且用到了gpiolib的人使用的
剩下的还有另外一类函数,这类函数是gpiolib内部自己的一些功能实现的代码

GPIOLIB自己的创建:
status = class_register(&gpio_class);
postcore_initcall(gpiolib_sysfs_init);

static struct class gpio_class = {
.name = “gpio”,
.owner = THIS_MODULE,

.class_attrs =	gpio_class_attrs,

};

static struct class_attribute gpio_class_attrs[] = {
__ATTR(export, 0200, NULL, export_store),
__ATTR(unexport, 0200, NULL, unexport_store),
__ATTR_NULL,
};
这个类创建的时候,有两个属性文件,export_store和unexport_store。
注意:.class_attrs 是这个类的属性文件,例如:/sys/class/gpio/export和
/sys/class/gpio/unexport,是这个类的属性文件。
而:leds_class->dev_attrs = led_class_attrs;这种是将来这个类device_create创建的文件的属性。一个是属于类的,一个是属于类的文件的。

gpiolib初始化函数:
gpiolib_sysfs_init
调用:
class_register 创建gpio类
gpiochip_export 创建gpio类下面的gpiochipn
调用:
status = sysfs_create_group(&dev->kobj,
&gpiochip_attr_group);
去创建gpiochipn下面的属性文件。
关于GPIO原理本身的一些东西,我们就不去深入研究了


目录和文件结构:
mach-s5pv210/gpiolib.c s5pv210_gpiolib_init
mach-s5pv210/include/mach/gpio.h #define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
arch/arm/plat-samsung/gpiolib.c 里面是210/6410这种4bit CON寄存器类型的操作方法
arch/arm/plat-samsung/gpio.c 里面是24XX这种2bit CON寄存器类型的操作方法
drivers/gpio/gpiolib.c 里面是内核开发者提供的gpiolib的驱动框架部分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值