nanzh

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

资料整理的迅为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         }, {
...

    1.3.1.1   .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上面截图中的内容

    1.3.1.2   .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的映射关系。

以上

posted on 2020-03-14 19:10  深海里的星星nanzh  阅读(791)  评论(0编辑  收藏  举报