zoukankan      html  css  js  c++  java
  • iTOP4412设备驱动学习六--GPIO的初始化和调用

    资料整理的迅为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的映射关系。

    以上

  • 相关阅读:
    测试杯子
    如何测试网页的登录页面
    功能性测试之边界值测试
    自动化 sample
    软件架构---敏捷和架构的关系
    软件架构---分布式后端架构应该考虑的一些方面
    软件架构---集群与负载均衡
    软件架构---从需求明确架构设计驱动力
    软件架构---质量属性的实现
    软件架构---质量属性(二)
  • 原文地址:https://www.cnblogs.com/nanzh/p/12493657.html
Copyright © 2011-2022 走看看