资料整理的迅为Linux视频教程
本节整理的是GPIO的初始化和调用。
验证:对宏EXYNOS4_GPL2(0)的操作就是对4412芯片管脚AC21寄存器的操作。
1. GPIO初始化的源码
1.1 在源码中查看编译:
1 $ ls drivers/gpio/*.o
2 drivers/gpio/built-in.o drivers/gpio/gpio-exynos4.o drivers/gpio/gpiolib.o drivers/gpio/gpio-plat-samsung.o
通过.o文件判断gpio-exynos4被编译进了内核
1.2 查看drivers/gpio/gpio-exynos4.c文件:
1 $ cat drivers/gpio/gpio-exynos4.c
2 ....
3 core_initcall(exynos4_gpiolib_init); //代表在Linux初始化过程中会调用
1.2.1 初始化函数在源码目录的“include/linux/init.h”文件中定义,该头文件中定义了一系列的初始化函数,在Linux启动的过程中会按等级优先启动
# include/linux/init.h
196 #define core_initcall(fn) __define_initcall("1",fn,1) //level:0最高
167 /* initcalls are now grouped by functionality into separate
168 * subsections. Ordering inside the subsections is determined
169 * by link order.
170 * For backwards compatibility, initcall() puts the call in
171 * the device init subsection.
172 *
173 * The `id' arg to __define_initcall() is needed so that multiple initcalls
174 * can point at the same handler without causing duplicate-symbol build errors.
175 */
176
177 #define __define_initcall(level,fn,id) \
178 static initcall_t __initcall_##fn##id __used \
179 __attribute__((__section__(".initcall" level ".init"))) = fn
180
1.3 下面继续回到drivers/gpio/gpio-exynos4.c的初始化位置:
$ cat drivers/gpio/gpio-exynos4.c
....
core_initcall(exynos4_gpiolib_init); //代表在Linux初始化过程中会调用
518 static __init int exynos4_gpiolib_init(void)
519 {
520 struct s3c_gpio_chip *chip;
521 int i;
522 int nr_chips;
523
524 /* GPIO common part */
525
526 chip = exynos4_gpio_common_4bit; //引用了exynos4_gpio_common_4bit结构体,在本文件中定义。
527 nr_chips = ARRAY_SIZE(exynos4_gpio_common_4bit);
528
529 for (i = 0; i < nr_chips; i++, chip++) {
530 if (chip->config == NULL)
531 chip->config = &gpio_cfg;
532 if (chip->base == NULL)
533 pr_err("No allocation of base address for [common gpio]");
534 }
535
536 samsung_gpiolib_add_4bit_chips(exynos4_gpio_common_4bit, nr_chips);
537
538 /* Only 4210 GPIO part */
539 if (soc_is_exynos4210()) {
540 chip = exynos4210_gpio_4bit;
541 nr_chips = ARRAY_SIZE(exynos4210_gpio_4bit);
542
543 for (i = 0; i < nr_chips; i++, chip++) {
544 if (chip->config == NULL)
545 chip->config = &gpio_cfg;
546 if (chip->base == NULL)
547 pr_err("No allocation of base address [4210 gpio]");
548 }
549
550 samsung_gpiolib_add_4bit_chips(exynos4210_gpio_4bit, nr_chips);
551 } else {
552 /* Only 4212/4412 GPIO part */
553 chip = exynos4212_gpio_4bit;
554 nr_chips = ARRAY_SIZE(exynos4212_gpio_4bit);
555
556 for (i = 0; i < nr_chips; i++, chip++) {
557 if (chip->config == NULL)
558 chip->config = &gpio_cfg;
559 if (chip->base == NULL)
560 pr_err("No allocation of base address [4212 gpio]");
561 }
562
563 samsung_gpiolib_add_4bit_chips(exynos4212_gpio_4bit, nr_chips);
564 }
565
566 s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
567 s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
568
569 return 0;
570 }
1.3.1 exynos4_gpio_common_4bit结构体内容截取:
...
75 static struct s3c_gpio_chip exynos4_gpio_common_4bit[] = {
77 {
78 .base = S5P_VA_GPIO1,
79 .eint_offset = 0x0,
80 .group = 0,
81 .chip = {
82 .base = EXYNOS4_GPA0(0),
83 .ngpio = EXYNOS4_GPIO_A0_NR,
84 .label = "GPA0",
85 },
86 }, {
...
230 }, {
231 .base = (S5P_VA_GPIO2 + 0x100), //里面用到的VA代表虚拟地址,PA代表物理地址。此处偏移地址值来源于datasheet,下图
232 .eint_offset = 0x20, //中断相关的
233 .group = 22, //给GPIO分组
234 .chip = {
235 .base = EXYNOS4_GPL2(0), //宏定义EXYNOS4_GPL2(0)赋值给初始化函数.==>(./arch/arm/mach-exynos/include/mach/gpio-exynos4.h)
236 .ngpio = EXYNOS4_GPIO_L2_NR, //这一个小组里面有几个GPIO,可以通过手册查到:#define EXYNOS4_GPIO_L2_NR (8)
237 .label = "GPL2", //程序员需要关心的标志,也就是之前查看LEDpin脚所对应的那块
238 },
239 }, {
...
base = (S5P_VA_GPIO2 + 0x100),的理解
offset可以直接在datasheet中搜索GPL2得到:
S5P_VA_GPIO2的内容:
1 S5P_VA_GPIO2的定义在:./arch/arm/plat-s5p/include/plat/map-s5p.h
2 #define S5P_VA_GPIO2 S3C_ADDR(0x02240000)
3 S3C_ADDR的定义在:./arch/arm/plat-samsung/include/plat/map-base.h
4
5 /* Fit all our registers in at 0xF6000000 upwards, trying to use as
6 * little of the VA space as possible so vmalloc and friends have a
7 * better chance of getting memory.
8 *
9 * we try to ensure stuff like the IRQ registers are available for
10 * an single MOVS instruction (ie, only 8 bits of set data)
11 */
12
13 #define S3C_ADDR_BASE 0xF6000000 //使用的虚拟地址
14
15 #ifndef __ASSEMBLY__
16 #define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
17 #else
18 #define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
19 #endif
源码检索,S5P_VA_GPIO2在cpu-exynos[/arch/arm/mach-exynos/cpu-exynos4.c]中也使用了,是一个平台文件
/arch/arm/mach-exynos/cpu-exynos4.c的结构体数组中
1 arch/arm/mach-exynos/cpu-exynos4.c:
2 /* Initial IO mappings */
3 static struct map_desc exynos4_iodesc[] __initdata = {
4 ...
5 }, {
6 .virtual = (unsigned long)S5P_VA_GPIO2, //表示虚拟地址
7 .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO2), //表示物理地址
8 .length = SZ_4K, //表示映射的宽度,如:#define SZ_4K 0x00001000 [sizes.h]
9 .type = MT_DEVICE,
10 }, {
11 ...
12 };
13
14 EXYNOS4_PA_GPIO2的定义在./arch/arm/mach-exynos/include/mach/map-exynos4.h中
15 #define EXYNOS4_PA_GPIO2 0x11000000 //此处的物理地址就和基地址对应起来的,也就是datasheet的6.2.3.37上面截图中的内容
.base = EXYNOS4_GPL2(0)的理解和调用
1 .base = EXYNOS4_GPL2(0):
2 1)EXYNOS4_GPL2的定义在文件:./arch/arm/mach-exynos/include/mach/gpio-exynos4.h
3 #define EXYNOS4_GPL2(_nr) (EXYNOS4_GPIO_L2_START + (_nr))
4 2)EXYNOS4_GPIO_L2_START在枚举类型中定义
5 enum exynos4_gpio_number {
6 ...
7 EXYNOS4_GPIO_L2_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L1),枚举第17个
8 ...
9 };
10 3)EXYNOS4_GPIO_NEXT的宏定义
11 /* GPIO bank numbers */
12 #define EXYNOS4_GPIO_NEXT(__gpio) \
13 ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1) //此处的+是连接的意思,不是判断
14 4)CONFIG_S3C_GPIO_SPACE的定义在:./include/generated/autoconf.h:
15 #define CONFIG_S3C_GPIO_SPACE 0
2. GPIO初始化的简单概括:
1)平台文件分别定义好物理地址和虚拟地址
2)物理地址和虚拟地址之间的映射
在初始化中,引入了程序员需要使用的GPIO宏定义,并将宏定义装入chip结构体中
内核中已经写好了LED的使用,如下drivers/char/itop4412_leds.c:
drivers/char/itop4412_leds.c:
27 #if defined(CONFIG_CPU_TYPE_SCP_ELITE) || defined(CONFIG_CPU_TYPE_POP_ELITE) || defined(CONFIG_CPU_TYPE_POP2G_ELITE)
28 static int led_gpios[] = {
29 EXYNOS4_GPL2(0), //此处为什么用(0)呢??
30 EXYNOS4_GPK1(1),
31 };
32
33 #elif defined(CONFIG_CPU_TYPE_SCP_SUPPER) || defined(CONFIG_CPU_TYPE_POP_SUPPER) || defined(CONFIG_CPU_TYPE_POP2G_SUPPER)
34
35
36 static int led_gpios[] = {
37 #if defined(CONFIG_MTK_COMBO_COMM) || defined(CONFIG_MTK_COMBO_COMM_MODULE)
38 EXYNOS4_GPC0(2),
39 #else
40 EXYNOS4_GPX2(5),
41 #endif
42 EXYNOS4_GPX0(1),
43 };
44
45
46 #endif
在datasheet中的6.2.3.37 GPL2CON
且在ITOP4412_MAIN_CLASICS_V3_2.pdf中搜索如下:
然后搜索KP_CONL0,连接到了连接器上如下图:
连接器通上核心板,然后在核心板中搜索TOPEET_coreboard4412_scp.pdf:
对应的就是GPL2_0(复用的)。
3. GPIO的调用函数
配置头文件在:arch/arm/plat-samsung/include/plat/gpio-cfg.h
函数:s3c_gpio_cfgpin,参数1:EXYNOS4_GPL2(0),参数2:配置的状态参数
77 /**
78 * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
79 * @pin pin The pin number to configure.
80 * @to to The configuration for the pin's function.
81 *
82 * Configure which function is actually connected to the external
83 * pin, such as an gpio input, output or some form of special function
84 * connected to an internal peripheral block.
85 *
86 * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT
87 * or S3C_GPIO_SFN() to indicate one of the possible values that the helper
88 * will then generate the correct bit mask and shift for the configuration.
89 *
90 * If a bank of GPIOs all needs to be set to special-function 2, then
91 * the following code will work:
92 *
93 * for (gpio = start; gpio < end; gpio++)
94 * s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
95 *
96 * The @to parameter can also be a specific value already shifted to the
97 * correct position in the control register, although these are discouraged
98 * in newer kernels and are only being kept for compatibility.
99 */
100 extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
这个函数会调用一个结构体,具体的实现在文件./arch/arm/plat-samsung/gpio-config.c中:
./arch/arm/plat-samsung/gpio-config.c
24 int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
25 {
26 struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); //到结构体中获取chip内容
27 unsigned long flags;
28 int offset;
29 int ret;
30
31 if (!chip)
32 return -EINVAL;
33
34 offset = pin - chip->chip.base;
35
36 s3c_gpio_lock(chip, flags);
37 ret = s3c_gpio_do_setcfg(chip, offset, config); //将值传过去配置
38 s3c_gpio_unlock(chip, flags);
39
40 return ret;
41 }
42 EXPORT_SYMBOL(s3c_gpio_cfgpin);
这个函数中使用的结构体和1.3.1中使用的结构体是相同的。结构体的定义在./arch/arm/plat-samsung/include/plat/gpio-core.h:
./arch/arm/plat-samsung/include/plat/gpio-core.h
42 /**
43 * struct s3c_gpio_chip - wrapper for specific implementation of gpio
44 * @chip: The chip structure to be exported via gpiolib.
45 * @base: The base pointer to the gpio configuration registers.
46 * @group: The group register number for gpio interrupt support.
47 * @irq_base: The base irq number.
48 * @config: special function and pull-resistor control information.
49 * @lock: Lock for exclusive access to this gpio bank.
50 * @pm_save: Save information for suspend/resume support.
51 *
52 * This wrapper provides the necessary information for the Samsung
53 * specific gpios being registered with gpiolib.
54 *
55 * The lock protects each gpio bank from multiple access of the shared
56 * configuration registers, or from reading of data whilst another thread
57 * is writing to the register set.
58 *
59 * Each chip has its own lock to avoid any contention between different
60 * CPU cores trying to get one lock for different GPIO banks, where each
61 * bank of GPIO has its own register space and configuration registers.
62 */
63 struct s3c_gpio_chip {
64 struct gpio_chip chip;
65 struct s3c_gpio_cfg *config;
66 struct s3c_gpio_pm *pm;
67 void __iomem *base;
68 int irq_base;
69 int group;
70 unsigned int eint_offset;
71 spinlock_t lock;
72 #ifdef CONFIG_PM
73 u32 pm_save[4];
74 #endif
75 };
所以控制GPIO的时候通过处理函数加上类似EXYNOS4_GPL2(0)的宏定义,就可以操作GPIO。
大部分都是内核或平台已经做成了。
其他:
CPU不直接对register操作,因为CPU是对内存中的一大段一大段的处理,单个寄存器读取是对CPU的浪费。
虚拟地址和物理地址对应的数组,调用是在函数ioremap中,来实现gpio的映射关系。
以上