編寫按鍵驅動時,想知道內核是如何管理GPIO的,所以開始追蹤代碼,中間走了一些彎路,現記錄于此。
追蹤代碼之前,我猜測:第一,這部分代碼應該在系統set up階段執行;第二,GPIO的代碼應該在machine或者platform或者vendor相關的目錄下。事實證明,第一點是正確的,第二點基本是錯誤的,因為內核依靠對GPIO的抽象來管理之,這層抽象層給具體的machine留出了一些它們需要是實現的接口,這與其他的設備驅動框架在使用上是很類似的,當然,GPIO也是一種設備啊... ...所以,管理GPIO的多數代碼位于drivers/gpio/目錄下。
好了,開始走讀代碼,那么對于S5PV210這塊SoC,GPIO子系統的入口函數在哪里呢?在drivers/gpio/gpio-s5pv210.c中,入口函數的實現如下圖所示:
1 static __init int s5pv210_gpiolib_init(void)
2 {
3 struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
4 int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
5 int gpioint_group = 0;
6 int i = 0;
7
8 for (i = 0; i < nr_chips; i++, chip++) {
9 if (chip->config == NULL) {
10 chip->config = &gpio_cfg;
11 chip->group = gpioint_group++;
12 }
13 if (chip->base == NULL)
14 chip->base = S5PV210_BANK_BASE(i);
15 }
16
17 samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
18 s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
19
20 return 0;
21 }
22 core_initcall(s5pv210_gpiolib_init);
入口函數沒幾行代碼,但是下面所有的內容都要從它開始,所以一點一點來吧,這里先羅列一下下面要敘述的內容:
1. struct s3c_gpio_chip的內容,以及重要的數組s5pv210_gpio_4bit;
2. 上述結構體中的成員config和base;
3. samsung_gpiolib_add_4bit_chips()的分析,這部分比較長。
第一部分,struct s3c_gpio_chip的介紹以及重要的數組s5pv210_gpio_4bit
1 struct s3c_gpio_chip {
2 struct gpio_chip chip;
3 struct s3c_gpio_cfg *config;
4 struct s3c_gpio_pm *pm;
5 void __iomem *base;
6 int irq_base;
7 int group;
8 spinlock_t lock;
9 #ifdef CONFIG_PM
10 u32 pm_save[4];
11 #endif
12 };
從面向對象的角度來看,s3c_gpio_chip是gpio_chip的子類,但是又新增了一些新的屬性和操作。雖說它的名字是chip,但是一個s3c_gpio_chip描述的是一個GPIO bank,如GPA0、GPA1、GPB等等, 這一點在接著要介紹的數組s5pv210_gpio_4bit中得以清晰體現。
base成員表示的是當前bank的控制寄存器的起始虛擬地址,注意是虛擬地址。
pm_save[]用于功耗管理,進入低功耗模式之前將相關寄存器的值存到該數組中,退出低功耗模式時將該數組的內容回寫到各寄存器中。
config成員的類型是struct s3c_gpio_cfg,具體的結構是:
1 struct s3c_gpio_cfg {
2 unsigned int cfg_eint;
3
4 s3c_gpio_pull_t (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs);
5 int (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs,
6 s3c_gpio_pull_t pull);
7
8 unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs);
9 int (*set_config)(struct s3c_gpio_chip *chip, unsigned offs,
10 unsigned config);
11 };
可見config成員用于控制和查看當前bank的某個pin的上下拉電阻的狀態,以及設置和查看某引腳上的復用功能,這個成員作為子類struct s3c_gpio_cfg的新成員,說明以上這兩種功能在不同的machine以及GPIO IP上的差別是不能忽略的。
struct s3c_gpio_cfg中很重要的一個成員就是它的父類struct gpio_chip,它內容很多,不過看成員名字就基本能明白含義:
1 struct gpio_chip {
2 const char *label;
3 struct device *dev;
4 struct module *owner;
5
6 int (*request)(struct gpio_chip *chip,
7 unsigned offset);
8 void (*free)(struct gpio_chip *chip,
9 unsigned offset);
10
11 int (*direction_input)(struct gpio_chip *chip,
12 unsigned offset);
13 int (*get)(struct gpio_chip *chip,
14 unsigned offset);
15 int (*direction_output)(struct gpio_chip *chip,
16 unsigned offset, int value);
17 int (*set_debounce)(struct gpio_chip *chip,
18 unsigned offset, unsigned debounce);
19
20 void (*set)(struct gpio_chip *chip,
21 unsigned offset, int value);
22
23 int (*to_irq)(struct gpio_chip *chip,
24 unsigned offset);
25
26 void (*dbg_show)(struct seq_file *s,
27 struct gpio_chip *chip);
28 int base;
29 u16 ngpio;
30 const char *const *names;
31 unsigned can_sleep:1;
32 unsigned exported:1;
33
34 #if defined(CONFIG_OF_GPIO)
35 /*
36 * If CONFIG_OF is enabled, then all GPIO controllers described in the
37 * device tree automatically may have an OF translation
38 */
39 struct device_node *of_node;
40 int of_gpio_n_cells;
41 int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
42 const void *gpio_spec, u32 *flags);
43 #endif
44 };
這個結構體中的request free等函數指針與gpio的request、free、direction_input、direction_output等函數的實現有關系。
接著看一下數組s5pv210_gpio_4bit,首先,這個名字中包含4bit,意思是每個bank的gpio控制寄存器中,每4bit控制一個gpio pin。這個數組很長,我們只取出個別元素看一下:
1 static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
2 {
3 .chip = {
4 .base = S5PV210_GPA0(0),
5 .ngpio = S5PV210_GPIO_A0_NR,
6 .label = 'GPA0',
7 },
8 }, {
9 .chip = {
10 .base = S5PV210_GPA1(0),
11 .ngpio = S5PV210_GPIO_A1_NR,
12 .label = 'GPA1',
13 },
14 }, {
15 .chip = {
16 .base = S5PV210_GPB(0),
17 .ngpio = S5PV210_GPIO_B_NR,
18 .label = 'GPB',
19 },
20 },
21 ... ... ... ... ... ... ... ...
22 {
23 .base = (S5P_VA_GPIO + 0xC40),
24 .config = &gpio_cfg_noint,
25 .irq_base = IRQ_EINT(16),
26 .chip = {
27 .base = S5PV210_GPH2(0),
28 .ngpio = S5PV210_GPIO_H2_NR,
29 .label = 'GPH2',
30 .to_irq = samsung_gpiolib_to_irq,
31 },
32 }, {
33 .base = (S5P_VA_GPIO + 0xC60),
34 .config = &gpio_cfg_noint,
35 .irq_base = IRQ_EINT(24),
36 .chip = {
37 .base = S5PV210_GPH3(0),
38 .ngpio = S5PV210_GPIO_H3_NR,
39 .label = 'GPH3',
40 .to_irq = samsung_gpiolib_to_irq,
41 },
42 },
43 };
這個數組描述了一些S5PV210上的gpio,但是對比數據手冊,有一些gpio并沒有出現在這里,但是這已經足夠多了,可以說這個數組描述了系統中多數能夠使用的gpio,并初始化了一些信息,比如當前bank的第一個pin的編號、這個bank中所有pin的數量等等,這些都是宏定義,具體的需要看mach-s5pv210相關的頭文件,由于涉及到的宏太多,而且沒什么難度,這里就不記錄了。
第二部分,struct s3c_gpio_chip中的config成員和base成員初始化。
這一部分的處理在s5pv210_gpiolib_init函數中,可以看到s5pv210_gpio_4bit中很多元素的config成員沒有初始化,也就是NULL,那么這里就需要給其賦值為gpio_cfg,這個變量就在當前文件中,定義如下:
1 static struct s3c_gpio_cfg gpio_cfg = {
2 .set_config = s3c_gpio_setcfg_s3c64xx_4bit,
上一篇:九鼎S5PV210開發板的SD卡啟動、uboot tftp升級內核鏡像
下一篇:UT-S5PV210開發板調通3G—WCDMA模塊
推薦閱讀最新更新時間:2025-05-02 11:58



設計資源 培訓 開發板 精華推薦
- 車充頭改A口
- LTC3588EDD-1 5V 至 16V 太陽能供電 2.5V 電源的典型應用電路,具有用于增加輸出能量存儲和電池備份的超級電容器
- LT6656AIS6-3.3、3.3V 2 端子電壓基準電流源的典型應用
- NCS29001 LED背光驅動器的典型應用
- Iru3034 具有限流功能的 8 引腳 PWM 開關控制器 IC 的典型應用
- LT1076HVCT7 基本正降壓轉換器的典型應用
- STEVAL-IKR002V7D、SPIRIT1 169-MHz 低數據速率收發器子板,帶范圍擴展器
- EVAL-L99MOD50XP、L99MOD50XPTR 汽車應用評估套件
- 具有 AEC-Q100 的 ZXLD1350 30V、350mA LED 驅動器的典型應用
- 靈活、高精度、低漂移、PLC/DCS 模擬輸出模塊
- 納祥科技2W 24位數字功放NX4920,可用于AI語音播報、WIFI播放器
- 常用解調器的定義和工作原理
- 從性能與網絡傳輸出發,講講鐵威馬MAX系列為什么一騎絕塵
- 惠普選中Hailo下一代人工智能加速器,革新零售業與酒店業運營模式
- 跨國商務溝通困局破解之道:時空壺 W4Pro 全場景應用解析
- 從矢量降噪到雙向同傳,時空壺 W4Pro 如何重構 AI 同傳技術標準?
- LoRa+NB-IoT雙模融合,地下車庫信號盲區電梯場景等的冗余通信
- LoRa與UWB的“定位之戰”,成本敏感場景高精度需求的場景切割
- 時空壺X1再升級:引領AI同傳新時代,革新演講翻譯體驗
- ARXML 規則下 ECU 總線通訊與 ADTF 測試方案