在内核源码目录下 ls drivers/gpio/*.o, 可以看到 gpioexynos4.c源文件最终被编译进了内核。
除了menuconfig配置文件,还可以通过.o文件来判定该文件是否编译进了内核
在 gpio-exynos4.c 文件最下面一行
core_initcall(exynos4_gpiolib_init);
core_initcall代表在linux初始化过程中会调用
初始化函数是在源码目录下 include/linux/init.h 文件中定义的,该头文件中定义了一系列的初始化函数,在linux启动的过程中会按等级。
初始化函数调用了 exynos4_gpiolib_init ---------------》
static __init int exynos4_gpiolib_init(void)
{
struct s3c_gpio_chip *chip;
int i;
int nr_chips;
/* GPIO common part */
chip = exynos4_gpio_common_4bit;
nr_chips = ARRAY_SIZE(exynos4_gpio_common_4bit);
for (i = 0; i < nr_chips; i++, chip++) {
if (chip->config == NULL)
chip->config = &gpio_cfg;
if (chip->base == NULL)
pr_err("No allocation of base address for [common gpio]");
}
samsung_gpiolib_add_4bit_chips(exynos4_gpio_common_4bit, nr_chips);
/* Only 4210 GPIO part */
if (soc_is_exynos4210()) {
chip = exynos4210_gpio_4bit;
nr_chips = ARRAY_SIZE(exynos4210_gpio_4bit);
for (i = 0; i < nr_chips; i++, chip++) {
if (chip->config == NULL)
chip->config = &gpio_cfg;
if (chip->base == NULL)
pr_err("No allocation of base address [4210 gpio]");
}
samsung_gpiolib_add_4bit_chips(exynos4210_gpio_4bit, nr_chips);
} else {
/* Only 4212/4412 GPIO part */
chip = exynos4212_gpio_4bit;
nr_chips = ARRAY_SIZE(exynos4212_gpio_4bit);
for (i = 0; i < nr_chips; i++, chip++) {
if (chip->config == NULL)
chip->config = &gpio_cfg;
if (chip->base == NULL)
pr_err("No allocation of base address [4212 gpio]");
}
samsung_gpiolib_add_4bit_chips(exynos4212_gpio_4bit, nr_chips);
}
s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
return 0;
}
在该函数中引用了chip = exynos4_gpio_common_4bit结构体
static struct s3c_gpio_chip exynos4_gpio_common_4bit[] = {
{
.base = S5P_VA_GPIO1,
.eint_offset = 0x0,
.group = 0,
.chip = {
.base = EXYNOS4_GPA0(0),
.ngpio = EXYNOS4_GPIO_A0_NR,
.label = "GPA0",
},
}, {
.base = (S5P_VA_GPIO1 + 0x20),
.eint_offset = 0x4,
.group = 1,
.chip = {
.base = EXYNOS4_GPA1(0),
.ngpio = EXYNOS4_GPIO_A1_NR,
.label = "GPA1",
},
}, {
.base = (S5P_VA_GPIO1 + 0x40),
.eint_offset = 0x8,
.group = 2,
.chip = {
.base = EXYNOS4_GPB(0),
.ngpio = EXYNOS4_GPIO_B_NR,
.label = "GPB",
},
}, {
.base = (S5P_VA_GPIO1 + 0x60),
.eint_offset = 0xC,
.group = 3,
.chip = {
.base = EXYNOS4_GPC0(0),
.ngpio = EXYNOS4_GPIO_C0_NR,
.label = "GPC0",
},
}, {
.base = (S5P_VA_GPIO1 + 0x80),
.eint_offset = 0x10,
.group = 4,
.chip = {
.base = EXYNOS4_GPC1(0),
.ngpio = EXYNOS4_GPIO_C1_NR,
.label = "GPC1",
},
}, {
.base = (S5P_VA_GPIO1 + 0xA0),
.eint_offset = 0x14,
.group = 5,
.chip = {
.base = EXYNOS4_GPD0(0),
.ngpio = EXYNOS4_GPIO_D0_NR,
.label = "GPD0",
},
}, {
.base = (S5P_VA_GPIO1 + 0xC0),
.eint_offset = 0x18,
.group = 6,
.chip = {
.base = EXYNOS4_GPD1(0),
.ngpio = EXYNOS4_GPIO_D1_NR,
.label = "GPD1",
},
}, {
.base = (S5P_VA_GPIO1 + 0x180),
.eint_offset = 0x30,
.group = 7,
.chip = {
.base = EXYNOS4_GPF0(0),
.ngpio = EXYNOS4_GPIO_F0_NR,
.label = "GPF0",
},
}, {
.base = (S5P_VA_GPIO1 + 0x1A0),
.eint_offset = 0x34,
.group = 8,
.chip = {
.base = EXYNOS4_GPF1(0),
.ngpio = EXYNOS4_GPIO_F1_NR,
.label = "GPF1",
},
}, {
.base = (S5P_VA_GPIO1 + 0x1C0),
.eint_offset = 0x38,
.group = 9,
.chip = {
.base = EXYNOS4_GPF2(0),
.ngpio = EXYNOS4_GPIO_F2_NR,
.label = "GPF2",
},
}, {
.base = (S5P_VA_GPIO1 + 0x1E0),
.eint_offset = 0x3C,
.group = 10,
.chip = {
.base = EXYNOS4_GPF3(0),
.ngpio = EXYNOS4_GPIO_F3_NR,
.label = "GPF3",
},
}, {
.base = (S5P_VA_GPIO2 + 0x40),
.eint_offset = 0x8,
.group = 16,
.chip = {
.base = EXYNOS4_GPK0(0),
.ngpio = EXYNOS4_GPIO_K0_NR,
.label = "GPK0",
},
}, {
.base = (S5P_VA_GPIO2 + 0x60),
.eint_offset = 0xC,
.group = 17,
.chip = {
.base = EXYNOS4_GPK1(0),
.ngpio = EXYNOS4_GPIO_K1_NR,
.label = "GPK1",
},
}, {
.base = (S5P_VA_GPIO2 + 0x80),
.eint_offset = 0x10,
.group = 18,
.chip = {
.base = EXYNOS4_GPK2(0),
.ngpio = EXYNOS4_GPIO_K2_NR,
.label = "GPK2",
},
}, {
.base = (S5P_VA_GPIO2 + 0xA0),
.eint_offset = 0x14,
.group = 19,
.chip = {
.base = EXYNOS4_GPK3(0),
.ngpio = EXYNOS4_GPIO_K3_NR,
.label = "GPK3",
},
}, {
.base = (S5P_VA_GPIO2 + 0xC0),
.eint_offset = 0x18,
.group = 20,
.chip = {
.base = EXYNOS4_GPL0(0),
.ngpio = EXYNOS4_GPIO_L0_NR,
.label = "GPL0",
},
}, {
.base = (S5P_VA_GPIO2 + 0xE0),
.eint_offset = 0x1C,
.group = 21,
.chip = {
.base = EXYNOS4_GPL1(0),
.ngpio = EXYNOS4_GPIO_L1_NR,
.label = "GPL1",
},
}, {
.base = (S5P_VA_GPIO2 + 0x100),
.eint_offset = 0x20,
.group = 22,
.chip = {
.base = EXYNOS4_GPL2(0),
.ngpio = EXYNOS4_GPIO_L2_NR,
.label = "GPL2",
},
}, {
.base = (S5P_VA_GPIO2 + 0x120),
.config = &gpio_cfg_noint,
.chip = {
.base = EXYNOS4_GPY0(0),
.ngpio = EXYNOS4_GPIO_Y0_NR,
.label = "GPY0",
},
}, {
.base = (S5P_VA_GPIO2 + 0x140),
.config = &gpio_cfg_noint,
.chip = {
.base = EXYNOS4_GPY1(0),
.ngpio = EXYNOS4_GPIO_Y1_NR,
.label = "GPY1",
},
}, {
.base = (S5P_VA_GPIO2 + 0x160),
.config = &gpio_cfg_noint,
.chip = {
.base = EXYNOS4_GPY2(0),
.ngpio = EXYNOS4_GPIO_Y2_NR,
.label = "GPY2",
},
}, {
.base = (S5P_VA_GPIO2 + 0x180),
.config = &gpio_cfg_noint,
.chip = {
.base = EXYNOS4_GPY3(0),
.ngpio = EXYNOS4_GPIO_Y3_NR,
.label = "GPY3",
},
}, {
.base = (S5P_VA_GPIO2 + 0x1A0),
.config = &gpio_cfg_noint,
.chip = {
.base = EXYNOS4_GPY4(0),
.ngpio = EXYNOS4_GPIO_Y4_NR,
.label = "GPY4",
},
}, {
.base = (S5P_VA_GPIO2 + 0x1C0),
.config = &gpio_cfg_noint,
.chip = {
.base = EXYNOS4_GPY5(0),
.ngpio = EXYNOS4_GPIO_Y5_NR,
.label = "GPY5",
},
}, {
.base = (S5P_VA_GPIO2 + 0x1E0),
.config = &gpio_cfg_noint,
.chip = {
.base = EXYNOS4_GPY6(0),
.ngpio = EXYNOS4_GPIO_Y6_NR,
.label = "GPY6",
},
}, {
.base = (S5P_VA_GPIO2 + 0xC00),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(0),
.chip = {
.base = EXYNOS4_GPX0(0),
.ngpio = EXYNOS4_GPIO_X0_NR,
.label = "GPX0",
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = (S5P_VA_GPIO2 + 0xC20),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(8),
.chip = {
.base = EXYNOS4_GPX1(0),
.ngpio = EXYNOS4_GPIO_X1_NR,
.label = "GPX1",
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = (S5P_VA_GPIO2 + 0xC40),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(16),
.chip = {
.base = EXYNOS4_GPX2(0),
.ngpio = EXYNOS4_GPIO_X2_NR,
.label = "GPX2",
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = (S5P_VA_GPIO2 + 0xC60),
.config = &gpio_cfg_noint,
.irq_base = IRQ_EINT(24),
.chip = {
.base = EXYNOS4_GPX3(0),
.ngpio = EXYNOS4_GPIO_X3_NR,
.label = "GPX3",
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = S5P_VA_GPIO3,
.chip = {
.base = EXYNOS4_GPZ(0),
.ngpio = EXYNOS4_GPIO_Z_NR,
.label = "GPZ",
},
},
};
#if defined(CONFIG_MTK_COMBO_COMM) || defined(CONFIG_MTK_COMBO_COMM_MODULE) //add by cym 20130301
EXPORT_SYMBOL(exynos4_gpio_common_4bit);
#endif
static struct s3c_gpio_chip exynos4210_gpio_4bit[] = {
{
.base = (S5P_VA_GPIO1 + 0xE0),
.eint_offset = 0x1C,
.group = 11,
.chip = {
.base = EXYNOS4210_GPE0(0),
.ngpio = EXYNOS4210_GPIO_E0_NR,
.label = "GPE0",
},
}, {
.base = (S5P_VA_GPIO1 + 0x100),
.eint_offset = 0x20,
.group = 12,
.chip = {
.base = EXYNOS4210_GPE1(0),
.ngpio = EXYNOS4210_GPIO_E1_NR,
.label = "GPE1",
},
}, {
.base = (S5P_VA_GPIO1 + 0x120),
.eint_offset = 0x24,
.group = 13,
.chip = {
.base = EXYNOS4210_GPE2(0),
.ngpio = EXYNOS4210_GPIO_E2_NR,
.label = "GPE2",
},
}, {
.base = (S5P_VA_GPIO1 + 0x140),
.eint_offset = 0x28,
.group = 14,
.chip = {
.base = EXYNOS4210_GPE3(0),
.ngpio = EXYNOS4210_GPIO_E3_NR,
.label = "GPE3",
},
}, {
.base = (S5P_VA_GPIO1 + 0x160),
.eint_offset = 0x2C,
.group = 15,
.chip = {
.base = EXYNOS4210_GPE4(0),
.ngpio = EXYNOS4210_GPIO_E4_NR,
.label = "GPE4",
},
}, {
.base = S5P_VA_GPIO2,
.group = 23,
.eint_offset = 0x0,
.chip = {
.base = EXYNOS4210_GPJ0(0),
.ngpio = EXYNOS4210_GPIO_J0_NR,
.label = "GPJ0",
},
}, {
.base = (S5P_VA_GPIO2 + 0x20),
.eint_offset = 0x4,
.group = 24,
.chip = {
.base = EXYNOS4210_GPJ1(0),
.ngpio = EXYNOS4210_GPIO_J1_NR,
.label = "GPJ1",
},
},
};
static struct s3c_gpio_chip exynos4212_gpio_4bit[] = {
{
.base = (S5P_VA_GPIO1 + 0x240),
.eint_offset = 0x40,
.group = 11,
.chip = {
.base = EXYNOS4212_GPJ0(0),
.ngpio = EXYNOS4212_GPIO_J0_NR,
.label = "GPJ0",
},
}, {
.base = (S5P_VA_GPIO1 + 0x260),
.eint_offset = 0x44,
.group = 12,
.chip = {
.base = EXYNOS4212_GPJ1(0),
.ngpio = EXYNOS4212_GPIO_J1_NR,
.label = "GPJ1",
}
}, {
.base = (S5P_VA_GPIO2 + 0x260),
.eint_offset = 0x24,
.group = 23,
.chip = {
.base = EXYNOS4212_GPM0(0),
.ngpio = EXYNOS4212_GPIO_M0_NR,
.label = "GPM0",
},
}, {
.base = (S5P_VA_GPIO2 + 0x280),
.eint_offset = 0x28,
.group = 24,
.chip = {
.base = EXYNOS4212_GPM1(0),
.ngpio = EXYNOS4212_GPIO_M1_NR,
.label = "GPM1",
},
}, {
.base = (S5P_VA_GPIO2 + 0x2A0),
.eint_offset = 0x2C,
.group = 25,
.chip = {
.base = EXYNOS4212_GPM2(0),
.ngpio = EXYNOS4212_GPIO_M2_NR,
.label = "GPM2",
},
}, {
.base = (S5P_VA_GPIO2 + 0x2C0),
.eint_offset = 0x30,
.group = 26,
.chip = {
.base = EXYNOS4212_GPM3(0),
.ngpio = EXYNOS4212_GPIO_M3_NR,
.label = "GPM3",
},
}, {
.base = (S5P_VA_GPIO2 + 0x2E0),
.eint_offset = 0x34,
.group = 27,
.chip = {
.base = EXYNOS4212_GPM4(0),
.ngpio = EXYNOS4212_GPIO_M4_NR,
.label = "GPM4",
},
}, {
.base = S5P_VA_GPIO4,
.chip = {
.base = EXYNOS4212_GPV0(0),
.ngpio = EXYNOS4212_GPIO_V0_NR,
.label = "GPV0",
},
}, {
.base = (S5P_VA_GPIO4 + 0x20),
.chip = {
.base = EXYNOS4212_GPV1(0),
.ngpio = EXYNOS4212_GPIO_V1_NR,
.label = "GPV1",
},
}, {
.base = (S5P_VA_GPIO4 + 0x60),
.chip = {
.base = EXYNOS4212_GPV2(0),
.ngpio = EXYNOS4212_GPIO_V2_NR,
.label = "GPV2",
},
}, {
.base = (S5P_VA_GPIO4 + 0x80),
.chip = {
.base = EXYNOS4212_GPV3(0),
.ngpio = EXYNOS4212_GPIO_V3_NR,
.label = "GPV3",
},
}, {
.base = (S5P_VA_GPIO4 + 0xC0),
.chip = {
.base = EXYNOS4212_GPV4(0),
.ngpio = EXYNOS4212_GPIO_V4_NR,
.label = "GPV4",
},
},
};
结构体中有S5P_VA_XXXX的基地址定义,VA一般用来代表虚拟地址。
.base = (S5P_VA_GPIO2 + 0x100),
.eint_offset = 0x20,
.group = 22,
.chip = {
.base = EXYNOS4_GPL2(0),
.ngpio = EXYNOS4_GPIO_L2_NR,
.label = "GPL2",
},
.base = (S5P_VA_GPIO2 + 0x100)
表示偏移地址和虚拟地址相加
.eint_offset = 0x20
表示中断部分
.group = 22
给GPIO分组
chip.base = EXYNOS4_GPL2(0)
宏定义EXYNOS4_GPL2(0)赋值给初始化函数
chip.ngpio = EXYNOS4_GPIO_L2_NR
表示这一小组中有几个GPIO
chip.label = “GPL2”
程序员需要关心的标志
EXYNOS4_GPL2(_nr) (EXYNOS4_GPIO_L2_START + (_nr))
EXYNOS4_GPIO_L2_START= EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L1)
EXYNOS4_GPIO_NEXT宏定义
#define EXYNOS4_GPIO_NEXT(__gpio) \ ((__gpio##_START) + (__gpio##_NR)
虚拟地址
查找S5P_VA_GPIO2宏定义,可以看到所有的GPIO被分为4个bank,这个和datasheet上面是一致的。
S5P_VA_GPIO1
S5P_VA_GPIO2 S3C_ADDR(0x02240000)
S5P_VA_GPIO3
S5P_VA_GPIO4
查找到S3C_ADDR宏定义
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
查找到S3C_ADDR_BASE宏定义,这是一个虚拟地址,可以看出,地址范围超出了1G或者2G内存的范围
#define S3C_ADDR_BASE 0xF6000000
查找该函数,可以看到进入函数就会调用chip结构体
3c_gpiolib_getchip,这个函数通过pin调用之后,会返回s3c_gpios[chip] 的参数
exynos4_gpio_common_4bit[]和s3c_gpios都是结构体s3c_gpio_chip类型的数据,然后计算偏移地址等等一系列操作,这一部分是linux内核以及三星平台完成。