1. 程式人生 > >linux GPIO子系統核心原始碼追蹤

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