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;
}
**一個非常重要的結構體:
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,
};
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的驅動框架部分
總結
以上是生活随笔為你收集整理的linux内核的gpiolib的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cherry-pick的定义和使用方法
- 下一篇: zlib解压 被压缩的PDF(关键字Fl