linux GPIO子系统内核源码追踪

提到GPIO 子系统,我们先来追踪下GPIO 子系统的接口函数是如何添加到内核中的?

初次追踪GPIO 子系统源码,逻辑有点乱,后续再次梳理;但有1点已经很明确:GPIO 子系统初始化 设备的gpio PIN引脚,已有初步的了解和认识;

内核编译时,已将GPIO 子系统编译进内核,所以驱动程序若想要要使用GPIO 子系统接口函数,只需按编写驱动程序一般步骤、GPIO 子系统接口函数调用顺序,进行初始化即可。

参考博客:https://blog.csdn.net/kuangzuxiaoN/article/details/55517931,在此表示感谢

【01】首先查看那些 gpio 文件被编译进内核

ls -l /linux-3.5/drivers/gpio/*.o,
"/linux-3.5/drivers/gpio/gpio-samsung.c"

【02】 core_initcall() 函数的入口调用函数

在该文件中,找到 core_initcall() 函数的入口调用函数;

3264 core_initcall(samsung_gpiolib_init);
3265 
3266 int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
3267 {
3268     struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
3269     unsigned long flags;

【03】查看函数 samsung_gpiolib_init()

查看函数 samsung_gpiolib_init(),找到 exynos4412 的gpio初始化的位置;

2972 /* TODO: cleanup soc_is_* */
2973 static __init int samsung_gpiolib_init(void)
2974 {
2975     struct samsung_gpio_chip *chip;
2976     int i, nr_chips;
2977 #if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_SOC_EXYNOS5250)
2978     void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
2979 #endif
2980     int group = 0;
2981 
2982     samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfg     s));
2983 
2984     if (soc_is_s3c24xx()) {
2985         s3c24xx_gpiolib_add_chips(s3c24xx_gpios,
2986                 ARRAY_SIZE(s3c24xx_gpios), S3C24XX_VA_GPIO);
2987     } else if (soc_is_s3c64xx()) {
2988         samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit,
。。。。。。	// 【如下为 exynos4x21 的初始化位置:soc_is_exynos4412()】
。。。。。。	// 【chip = chip_p = exynos4x12_gpios_1;】
3044     } else if (soc_is_exynos4210() || soc_is_exynos4212() ||
3045             soc_is_exynos4412()) {
3046 #ifdef CONFIG_ARCH_EXYNOS4
3047         struct samsung_gpio_chip *chip_p;
3048         int offset = 0;
3049         int group1 = 0;
3050 
3051         /* gpio part1 */
3052         gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
3053         if (gpio_base1 == NULL) {
3054             pr_err("unable to ioremap for gpio_base1\n");
3055             goto err_ioremap1;
3056         }
3057 
3058         if (soc_is_exynos4210()) {
3059             chip = chip_p = exynos4210_gpios_1;
3060             nr_chips = ARRAY_SIZE(exynos4210_gpios_1);
3061         } else {	// 【chip = chip_p = exynos4x12_gpios_1;】
3062             chip = chip_p = exynos4x12_gpios_1;
3063             nr_chips = ARRAY_SIZE(exynos4x12_gpios_1);
3064         }
3065 
3066         for (i = 0; i < nr_chips; i++, chip++) {
3067             if (!chip->config) {
3068                 chip->config = &exynos_gpio_cfg;
3069                 if (chip->group)
3070                     group = chip->group;
3071                 chip->group = group++;
3072             }
3073 
3074             if (chip->base)
3075                 offset = (u32)chip->base;
3076             chip->base = gpio_base1 + offset;
3077             offset += 0x20;
3078 
3079             exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO1, 0);
3080         }
3081         samsung_gpiolib_add_4bit_chips(chip_p, nr_chips, gpio_base1);
3082         group1 = group;
3083 
3084         /* gpio part2 */
3085         gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
3086         if (gpio_base2 == NULL) {
3087             pr_err("unable to ioremap for gpio_base2\n");
3088             goto err_ioremap2;
3089         }
3090 
3091         if (soc_is_exynos4210()) {
3092             chip = chip_p = exynos4210_gpios_2;
3093             nr_chips = ARRAY_SIZE(exynos4210_gpios_2);
3094         } else {
3095             chip = chip_p = exynos4x12_gpios_2;
3096             nr_chips = ARRAY_SIZE(exynos4x12_gpios_2);
3097         }
3098 
3099         offset = 0;
。。。。。。

【04】找到EXYNOS4412开发平台的代码逻辑

samsung_gpiolib_init() 函数定义了三星EXYNOS系列不同产品的GPIO,我的开发平台是EXYNOS4412,因此只看这部分就行了,如下所示:

3058         if (soc_is_exynos4210()) {
3059             chip = chip_p = exynos4210_gpios_1;
3060             nr_chips = ARRAY_SIZE(exynos4210_gpios_1);
3061         } else {
3062             chip = chip_p = exynos4x12_gpios_1;
3063             nr_chips = ARRAY_SIZE(exynos4x12_gpios_1);
3064         }

【05】exynos4x12_gpios_1[];  数组的定义

注意:chip = chip_p = exynos4x12_gpios_1; 这个结构体,跳转到exynos4x12_gpios_1定义的地方;
其在内核源码目录下./drivers/gpio/gpio-exynos4.c中:

2229 static struct samsung_gpio_chip exynos4x12_gpios_1[] = {
2230     {
2231         .chip   = {
2232             .base   = EXYNOS4_GPA0(0),
2233             .ngpio  = EXYNOS4_GPIO_A0_NR,
2234             .label  = "GPA0",
2235         },
2236     }, {
。。。。。。
。。。。。。
2552     }, {
2553         .base   = (void *)0x260,
2554         .chip   = {
2555             .base   = EXYNOS4X12_GPM0(0),
2556             .ngpio  = EXYNOS4X12_GPIO_M0_NR,
2557             .label  = "GPM0",
2558         },
2559     }, {
2560         .chip   = {
2561             .base   = EXYNOS4X12_GPM1(0),
2562             .ngpio  = EXYNOS4X12_GPIO_M1_NR,
2563             .label  = "GPM1",
2564         },
2565     }, {
2566         .chip   = {
2567             .base   = EXYNOS4X12_GPM2(0),
2568             .ngpio  = EXYNOS4X12_GPIO_M2_NR,
2569             .label  = "GPM2",
2570         },
2571     }, {
2572         .chip   = {
2573             .base   = EXYNOS4X12_GPM3(0),
2574             .ngpio  = EXYNOS4X12_GPIO_M3_NR,
2575             .label  = "GPM3",
2576         },
2577     }, {
2578         .chip   = {
2579             .base   = EXYNOS4X12_GPM4(0),
2580             .ngpio  = EXYNOS4X12_GPIO_M4_NR,
2581             .label  = "GPM4",
2582         },
2583     }, {
2584         .base   = (void *)0xC00,
2585         .config = &samsung_gpio_cfgs[9],
。。。。。。
。。。。。。
2611     }, {
2612         .config = &samsung_gpio_cfgs[9],
2613         .irq_base = IRQ_EINT(24),
2614         .chip   = {
2615             .base   = EXYNOS4_GPX3(0),
2616             .ngpio  = EXYNOS4_GPIO_X3_NR,
2617             .label  = "GPX3",
2618             .to_irq = samsung_gpiolib_to_irq,
2619         },
2620     },
2621 };

【06】samsung_gpio_chip结构体的定义

先来看这个结构体的定义:samsung_gpio_chip

42 /**
 43  * struct samsung_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 samsung_gpio_chip {
 64     struct gpio_chip    chip;
 65     struct samsung_gpio_cfg *config;
 66     struct samsung_gpio_pm  *pm;
 67     void __iomem        *base;
 68     int         irq_base;
 69     int         group;
 70     spinlock_t       lock;
 71 #ifdef CONFIG_PM
 72     u32         pm_save[5];
 73 #endif
 74 };

【07】结构体成员 chip结构体gpio_chip的定义

再来看其结构体成员 chip结构体:gpio_chip,如下所示,定义了gpio 操作的大部分函数,比如:
"/linux-3.5/include/asm-generic/gpio.h",文件中,比较常用的如下:
int         (*request)(struct gpio_chip *chip,
int         (*direction_input)(struct gpio_chip *chip,
int         (*direction_output)(struct gpio_chip *chip,
int         (*get)(struct gpio_chip *chip,
int         (*set_debounce)(struct gpio_chip *chip,


 92 struct gpio_chip {
 93     const char      *label;
 94     struct device       *dev;
 95     struct module       *owner;
 96 
 97     int         (*request)(struct gpio_chip *chip,
 98                         unsigned offset);
 99     void            (*free)(struct gpio_chip *chip,
100                         unsigned offset);
101 
102     int         (*direction_input)(struct gpio_chip *chip,
103                         unsigned offset);
104     int         (*get)(struct gpio_chip *chip,
105                         unsigned offset);
106     int         (*direction_output)(struct gpio_chip *chip,
107                         unsigned offset, int value);
108     int         (*set_debounce)(struct gpio_chip *chip,
109                         unsigned offset, unsigned debounce);
110 
111     void            (*set)(struct gpio_chip *chip,
112                         unsigned offset, int value);
113 
114     int         (*to_irq)(struct gpio_chip *chip,
115                         unsigned offset);
116 
117     void            (*dbg_show)(struct seq_file *s,
118                         struct gpio_chip *chip);
119     int         base;
120     u16         ngpio;
121     const char      *const *names;
122     unsigned        can_sleep:1;
123     unsigned        exported:1;
124 
125 #if defined(CONFIG_OF_GPIO)
126     /*
127      * If CONFIG_OF is enabled, then all GPIO controllers described in the
128      * device tree automatically may have an OF translation
129      */
130     struct device_node *of_node;
131     int of_gpio_n_cells;
132     int (*of_xlate)(struct gpio_chip *gc,
133                 const struct of_phandle_args *gpiospec, u32 *flags);
134 #endif
135 };

【08】再来看exynos4x12_gpios_1[]数组元素

在这里我们再回到前面结构体数组中的元素chip中的成员:GPM4,刚好对应 LED0——4;
分析基地址的数值:    .base   = EXYNOS4X12_GPM4(0),        // 宏定义

2552     }, {
2553         .base   = (void *)0x260,
2554         .chip   = {
2555             .base   = EXYNOS4X12_GPM0(0),
2556             .ngpio  = EXYNOS4X12_GPIO_M0_NR,
2557             .label  = "GPM0",
2558         },
2559     }, {
......
2577     }, {
2578         .chip   = {
2579             .base   = EXYNOS4X12_GPM4(0),		// 宏定义
2580             .ngpio  = EXYNOS4X12_GPIO_M4_NR,
2581             .label  = "GPM4",
2582         },
2583     }, {

EXYNOS4X12_GPM4(0)的定义如下:
"/linux-3.5/arch/arm/mach-exynos/include/mach/gpio.h"
注意:如下宏,把每个 GPIO 地址做了一下封装,根据宏名字就指导操作那个GPIO;

149 #define EXYNOS4X12_GPM0(_nr)    (EXYNOS4X12_GPIO_M0_START + (_nr))
150 #define EXYNOS4X12_GPM1(_nr)    (EXYNOS4X12_GPIO_M1_START + (_nr))
151 #define EXYNOS4X12_GPM2(_nr)    (EXYNOS4X12_GPIO_M2_START + (_nr))
152 #define EXYNOS4X12_GPM3(_nr)    (EXYNOS4X12_GPIO_M3_START + (_nr))
153 #define EXYNOS4X12_GPM4(_nr)    (EXYNOS4X12_GPIO_M4_START + (_nr))	// 宏定义
154 
155 #define EXYNOS4_GPX0(_nr)   (EXYNOS4_GPIO_X0_START + (_nr))

EXYNOS4X12_GPIO_M4_START,的定义为如下 exynos4_gpio_number 枚举类型的元素:

 69 /* EXYNOS4 GPIO bank numbers */
 70 
 71 enum exynos4_gpio_number {
 72     EXYNOS4_GPIO_A0_START   = 0,
 73     EXYNOS4_GPIO_A1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),
 74     EXYNOS4_GPIO_B_START    = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A1),
......
 89     EXYNOS4X12_GPIO_M3_START    = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M2),
 90     EXYNOS4X12_GPIO_M4_START    = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M3), // 宏定义
 91 
 92     EXYNOS4_GPIO_F0_START   = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M4),
......
115     EXYNOS4_GPIO_Y6_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y5),
116     EXYNOS4_GPIO_Z_START    = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y6),
117 };

再到 EXYNOS_GPIO_NEXT() 的定义处:

 15 /* Macro for EXYNOS GPIO numbering */
 16 
 17 #define EXYNOS_GPIO_NEXT(__gpio) \
 18     ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)

// 注意:##连接符号是把传递过来的参数当成字符串进行代替

根据以上可知:    .base   = EXYNOS4X12_GPM4(0),的结果:
因为:
#define EXYNOS4X12_GPM4(_nr)    (EXYNOS4X12_GPIO_M4_START + (_nr))    // 宏定义
EXYNOS4X12_GPIO_M4_START    = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M3),
#define EXYNOS_GPIO_NEXT(__gpio) \
     ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)

所以,最终:
====》EXYNOS4X12_GPM4(0)
=     EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M3) + 0;
=    ((EXYNOS4X12_GPIO_M3_START) + (EXYNOS4X12_GPIO_M3_NR) + CONFIG_S3C_GPIO_SPACE + 1) + 0;
即,很显然, EXYNOS4X12_GPM4(0) 就是:从GPM3的首地址 + GPM3个数 + GPM4的offset就是当前GPM4的IO偏移量;
所以这样一步一步传递,可以得出GPM4的地址。
计算方法可参见:https://blog.csdn.net/s762888517/article/details/9143381

即:89         EXYNOS4X12_GPIO_M3_START    = EXYNOS_GPIO_NEXT(EXYNOS4X12_GPIO_M2), 该地址可一直向前查找调用,最终可追溯到内存中 表示GPIO的最小地址;
53      #define EXYNOS4X12_GPIO_M3_NR   (8)
    CONFIG_S3C_GPIO_SPACE 宏定义,其值是0
【注意】
#define EXYNOS4X12_GPIO_M3_NR   (8) 含义是:
其对应GPM3CON控制寄存器,其中可以用作为GPIO分别是GPM3CON[7:0]共8个GPIO。

 50 #define EXYNOS4X12_GPIO_M0_NR   (8)
 51 #define EXYNOS4X12_GPIO_M1_NR   (7)
 52 #define EXYNOS4X12_GPIO_M2_NR   (5) //其对应GPM2CON控制寄存器,其中可以用作为GPIO分别是GPM3CON[4:0]共5个GPIO。
 53 #define EXYNOS4X12_GPIO_M3_NR   (8)
 54 #define EXYNOS4X12_GPIO_M4_NR   (8)

【09】GPIO底层的调用过程:

接下来再看一下GPIO底层的调用过程:
./arch/arm/plat-samsung/include/plat/gpio-cfg.h中定义了这几个函数

1)/*GPIO引脚功能配置*/

70 /* Defines for generic pin configurations */
 71 #define S3C_GPIO_INPUT  (S3C_GPIO_SPECIAL(0))
 72 #define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1))
 73 #define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x))
 74 
 75 #define samsung_gpio_is_cfg_special(_cfg) \
 76     (((_cfg) & S3C_GPIO_SPECIAL_MARK) == S3C_GPIO_SPECIAL_MARK)
 77 
 78 /**
 79  * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
 80  * @pin pin The pin number to configure.
 81  * @to to The configuration for the pin's function.
 82  *
 83  * Configure which function is actually connected to the external
 84  * pin, such as an gpio input, output or some form of special function
 85  * connected to an internal peripheral block.
 86  *
 87  * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT
 88  * or S3C_GPIO_SFN() to indicate one of the possible values that the helper
 89  * will then generate the correct bit mask and shift for the configuration.
......
 94  *  for (gpio = start; gpio < end; gpio++)
 95  *      s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
......
100  */
101 extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);

s3c_gpio_cfgpin() 函数实现原型:
/linux-3.5/drivers/gpio/gpio-samsung.c

3266 int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
3267 {
3268     struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
3269     unsigned long flags;
3270     int offset;
3271     int ret;
3272 
3273     if (!chip)
3274         return -EINVAL;
3275 
3276     offset = pin - chip->chip.base;
3277 
3278     samsung_gpio_lock(chip, flags);
3279     ret = samsung_gpio_do_setcfg(chip, offset, config);
3280     samsung_gpio_unlock(chip, flags);
3281 
3282     return ret;
3283 }
3284 EXPORT_SYMBOL(s3c_gpio_cfgpin);

2)/*操作GPIO子系统常用的接口函数*/

在内核源码目录下./include/linux/gpio.h中定义了这几个函数:

87 static inline bool gpio_is_valid(int number)
 88 {
 89     return false;
 90 }
 91 
 92 static inline int gpio_request(unsigned gpio, const char *label)
 93 {
 94     return -ENOSYS;
 95 }
 96 
 ......
103 static inline int gpio_request_one(unsigned gpio,
104                     unsigned long flags, const char *label)
105 {
106     return -ENOSYS;
107 }
108 
......
114 
115 static inline int gpio_request_array(const struct gpio *array, size_t num)
116 {
117     return -ENOSYS;
118 }
119 
120 static inline void gpio_free(unsigned gpio)
121 {
122     might_sleep();
123 
124     /* GPIO can never have been requested */
125     WARN_ON(1);
126 }
127 
......
135 
136 static inline void gpio_free_array(const struct gpio *array, size_t num)
137 {
138     might_sleep();
139 
140     /* GPIO can never have been requested */
141     WARN_ON(1);
142 }
143 
144 static inline int gpio_direction_input(unsigned gpio)
145 {
146     return -ENOSYS;
147 }
148 
149 static inline int gpio_direction_output(unsigned gpio, int value)
150 {
151     return -ENOSYS;
152 }
......
179 static inline int gpio_get_value_cansleep(unsigned gpio)
180 {
181     /* GPIO can never have been requested or set as {in,out}put */
182     WARN_ON(1);
183     return 0;
184 }
185 
186 static inline void gpio_set_value_cansleep(unsigned gpio, int value)
187 {
188     /* GPIO can never have been requested or set as output */
189     WARN_ON(1);
190 }
191 
192 static inline int gpio_export(unsigned gpio, bool direction_may_change)
193 {
194     /* GPIO can never have been requested or set as {in,out}put */
195     WARN_ON(1);
196     return -EINVAL;
197 }
......
220 static inline int gpio_to_irq(unsigned gpio)
221 {
222     /* GPIO can never have been requested or set as input */
223     WARN_ON(1);
224     return -EINVAL;
225 }
226 
227 static inline int irq_to_gpio(unsigned irq)
228 {
229     /* irq can never have been returned from gpio_to_irq() */
230     WARN_ON(1);
231     return -EINVAL;
232 }

3)GPIO子系统————驱动初始化一般步骤:

在驱动初始化时,直接调用这几个相关的函数就可以了,
首先,申请GPIO资源,调用gpio_request函数;
其次,配置GPIO引脚模式:输入、输出还是作其它用,调用s3c_gpio_cfgpin函数,这个函数的第二参数选择S3C_GPIO_INPUT、S3C_GPIO_OUTPUT、S3C_GPIO_SFN(x)三者之一就可以了;
然后,在应用层直接下发操作命令,比如使用ioctl命令进行操作设备文件,则内核解析命令码,再去操作GPIO实现功能;
最后,卸载驱动时,记得释放申请的GPIO,有始有终,这时调用gpio_free函数,一个简单的IO控制就可以这样完成。
---------------------借鉴博客:在此表示感谢!!!
作者:kuangzuxiaoN
来源:CSDN
原文:https://blog.csdn.net/kuangzuxiaoN/article/details/55517931
版权声明:本文为博主原创文章,转载请附上博文链接!

【遗留问题】

比如:EXYNOS4_GPA1(0),现在只是暂且认为EXYNOS4_GPA1(0)最终指的地址,就是 GPA1_CON寄存器的首地址,还没真正推算出来。

计算最前面两个:
1)计算地址:.base   = EXYNOS4X12_GPA0(0),
 121 #define EXYNOS4_GPA0(_nr)   (EXYNOS4_GPIO_A0_START + (_nr))

 71 enum exynos4_gpio_number {
 72     EXYNOS4_GPIO_A0_START   = 0,

所以:EXYNOS4X12_GPA0(0)
=    (EXYNOS4_GPIO_A0_START + (_nr))
=     0 + 0 = 0;

2)计算地址:EXYNOS4_GPA1(0)
 22 #define EXYNOS4_GPA1(_nr)   (EXYNOS4_GPIO_A1_START + (_nr))

 71 enum exynos4_gpio_number {
 72     EXYNOS4_GPIO_A0_START   = 0,
 73     EXYNOS4_GPIO_A1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),

 22 #define EXYNOS4_GPIO_A0_NR  (8)

所以:
#define EXYNOS_GPIO_NEXT(__gpio) \
     ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)

==》EXYNOS4_GPA1(0)
=    (EXYNOS4_GPIO_A1_START + (_nr))
=    (EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0) + 0);  
=    (((EXYNOS4_GPIO_A0_START) + (EXYNOS4_GPIO_A0_NR) + CONFIG_S3C_GPIO_SPACE + 1) + 0)
    (GPA0首地址    +    GPA0个数    +    0 + 1)    +    GPA0的offset)
=    0    +    8    +    1    +    0
=    9


 71 enum exynos4_gpio_number {
 72     EXYNOS4_GPIO_A0_START   = 0,
 73     EXYNOS4_GPIO_A1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),

 17 #define EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0) \
 18     ((EXYNOS4_GPIO_A0_START) + (EXYNOS4_GPIO_A0_NR) + CONFIG_S3C_GPIO_SPACE + 1)


本文GPIO子系统代码追踪,参考如下博客文章,在此表示感谢,写的不错,赞一个。
https://blog.csdn.net/kuangzuxiaoN/article/details/55517931?locationNum=2&fps=1


 42 #ifdef CONFIG_GENERIC_GPIO
 43
 44 #ifdef CONFIG_ARCH_HAVE_CUSTOM_GPIO_H
 45 #include <asm/gpio.h>
 46 #else
 47
 48 #include <asm-generic/gpio.h>
 
头文件区别:
https://blog.csdn.net/lk07828/article/details/44245577?locationNum=10

猜你喜欢

转载自blog.csdn.net/llzhang_fly/article/details/83691345