提到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