加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
    • pinctrl
    • sysfs 訪問方法
    • gpio
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

一文搞懂 | Linux pinctrl/gpio子系統(tǒng)

2023/02/22
3644
閱讀需 45 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

pinctrl 子系統(tǒng)和 gpio 子系統(tǒng)雖然難度不大,但在內(nèi)核里的使用率非常高,本文爭(zhēng)取一次性把相關(guān)內(nèi)容介紹一遍。

pinctrl

數(shù)據(jù)結(jié)構(gòu)

使用 struct pinctrl_desc 抽象一個(gè) pin controller,該結(jié)構(gòu)的定義如下:

struct?pinctrl_desc?{
?const?char?*name;
?const?struct?pinctrl_pin_desc?*pins;
?unsigned?int?npins;
?const?struct?pinctrl_ops?*pctlops;
?const?struct?pinmux_ops?*pmxops;
?const?struct?pinconf_ops?*confops;
?struct?module?*owner;
#ifdef?CONFIG_GENERIC_PINCONF
?unsigned?int?num_custom_params;
?const?struct?pinconf_generic_params?*custom_params;
?const?struct?pin_config_item?*custom_conf_items;
#endif
};
    pins

變量 pins 和 npins 把系統(tǒng)中所有的 pin 描述出來,并建立索引。驅(qū)動(dòng)為了和具體的 pin 對(duì)應(yīng)上,再將這些描述的這些 pin 組織成一個(gè) struct pinctrl_pin_desc 類型的數(shù)組,該類型的定義為:

struct?pinctrl_pin_desc?{
?unsigned?number;
?const?char?*name;
?void?*drv_data;
};
    pin groups

SoC中,有時(shí)需要將很多 pin 組合在一起,以實(shí)現(xiàn)特定的功能,例如 uart 接口、i2c 接口等。因此 pin controller 需要以 group 為單位,訪問、控制多個(gè) pin,這就是 pin groups。

struct?group_desc?{
?const?char?*name;
?int?*pins;
?int?num_pins;
?void?*data;
};

pinctrl core在struct pinctrl_ops中抽象出三個(gè)回調(diào)函數(shù),用來獲取pin groups相關(guān)信息,如下:

struct?pinctrl_ops?{
??//獲取系統(tǒng)中pin?groups的個(gè)數(shù),后續(xù)的操作,將以相應(yīng)的索引為單位(類似數(shù)組的下標(biāo),個(gè)數(shù)為數(shù)組的大小)
?int?(*get_groups_count)?(struct?pinctrl_dev?*pctldev);
??//獲取指定group(由索引selector指定)的名稱
?const?char?*(*get_group_name)?(struct?pinctrl_dev?*pctldev,?unsigned?selector);
??//獲取指定group的所有pins(由索引selector指定),結(jié)果保存在pins(指針數(shù)組)和num_pins(指針)中
?int?(*get_group_pins)?(struct?pinctrl_dev?*pctldev,?unsigned?selector,?const?unsigned?**pins,?unsigned?*num_pins);
?void?(*pin_dbg_show)?(struct?pinctrl_dev?*pctldev,?struct?seq_file?*s,?unsigned?offset);
??//用于將device?tree中的pin?state信息轉(zhuǎn)換為pin?map
?int?(*dt_node_to_map)?(struct?pinctrl_dev?*pctldev,?struct?device_node?*np_config,?struct?pinctrl_map?**map,?unsigned?*num_maps);
?void?(*dt_free_map)?(struct?pinctrl_dev?*pctldev,?struct?pinctrl_map?*map,?unsigned?num_maps);
};

group 的組織方式是由驅(qū)動(dòng)決定的。

    pin configuration

除了上面的 pin 和 pin group,有些管腳可以配置,比如上拉,下拉,高阻等。pin configuration 來封裝這些功能,具體體現(xiàn)在 struct pinconf_ops 數(shù)據(jù)結(jié)構(gòu)中,如下:

struct?pinconf_ops?{
#ifdef?CONFIG_GENERIC_PINCONF
?bool?is_generic;
#endif
??//獲取指定?pin?的當(dāng)前配置,保存在?config?指針中
?int?(*pin_config_get)?(struct?pinctrl_dev?*pctldev,?unsigned?pin,?unsigned?long?*config);
??//設(shè)置指定pin的配置
?int?(*pin_config_set)?(struct?pinctrl_dev?*pctldev,?unsigned?pin,?unsigned?long?*configs,?unsigned?num_configs);
??//獲取指定pin?group的配置項(xiàng)
?int?(*pin_config_group_get)?(struct?pinctrl_dev?*pctldev,?unsigned?selector,?unsigned?long?*config);
??//設(shè)置指定pin?group的配置項(xiàng)
?int?(*pin_config_group_set)?(struct?pinctrl_dev?*pctldev,?unsigned?selector,?unsigned?long?*configs,?unsigned?num_configs);
??......
    pin mux

為了兼容不同的應(yīng)用場(chǎng)景,有很多管腳可以配置為不同的功能,例如A和B兩個(gè)管腳,既可以當(dāng)作普通的GPIO使用,又可以配置為I2C的的SCL和SDA,也可以配置為UART的TX和RX,這稱作管腳的復(fù)用(簡(jiǎn)稱 pin mux)。使用 struct pinmux_ops 來抽象 pin mux 有關(guān)的操作,如下:

struct?pinmux_ops?{
??//檢查某個(gè)pin是否已作它用,用于管腳復(fù)用時(shí)的互斥
?int?(*request)?(struct?pinctrl_dev?*pctldev,?unsigned?offset);
??//request的反操作
?int?(*free)?(struct?pinctrl_dev?*pctldev,?unsigned?offset);
??//獲取系統(tǒng)中function的個(gè)數(shù)
?int?(*get_functions_count)?(struct?pinctrl_dev?*pctldev);
??//獲取指定function的名稱
?const?char?*(*get_function_name)?(struct?pinctrl_dev?*pctldev,?unsigned?selector);
??//獲取指定function所占用的pin?group
?int?(*get_function_groups)?(struct?pinctrl_dev?*pctldev,?unsigned?selector,?const?char?*?const?**groups,?unsigned?*num_groups);
??//將指定的pin?group(group_selector)設(shè)置為指定的function(func_selector)
?int?(*set_mux)?(struct?pinctrl_dev?*pctldev,?unsigned?func_selector,?unsigned?group_selector);
??//以下是gpio相關(guān)的操作
?int?(*gpio_request_enable)?(struct?pinctrl_dev?*pctldev,?struct?pinctrl_gpio_range?*range,?unsigned?offset);
?void?(*gpio_disable_free)?(struct?pinctrl_dev?*pctldev,?struct?pinctrl_gpio_range?*range,?unsigned?offset);
?int?(*gpio_set_direction)?(struct?pinctrl_dev?*pctldev,?struct?pinctrl_gpio_range?*range,?unsigned?offset,?bool?input);
??//為true時(shí),說明該pin?controller不允許某個(gè)pin作為gpio和其它功能同時(shí)使用
?bool?strict;
};
    pin state

根據(jù)前面的描述,pinctrl driver 抽象出來了一些離散的對(duì)象:pin(pin group)、function、configuration,并實(shí)現(xiàn)了這些對(duì)象的控制和配置方式。然后我們回到某一個(gè)具體的 device 上(如 lpuart,usdhc)。一個(gè)設(shè)備在某一狀態(tài)下(如工作狀態(tài)、休眠狀態(tài)、等等),所使用的pin(pin group)、pin(pin group)的 function 和 configuration,是唯一確定的。所以固定的組合可以確定固定的狀態(tài),在設(shè)備樹里用 pinctrl-names 指明狀態(tài)名字,pinctrl-x 指明狀態(tài)引腳

    pin map

pin state 有關(guān)的信息是通過 pin map 收集,相關(guān)的數(shù)據(jù)結(jié)構(gòu)如下:

struct?pinctrl_map?{
??//device的名稱
?const?char?*dev_name;
??//pin?state的名稱
?const?char?*name;
??//該map的類型
?enum?pinctrl_map_type?type;
??//pin?controller?device的名字
?const?char?*ctrl_dev_name;
?union?{
??struct?pinctrl_map_mux?mux;
??struct?pinctrl_map_configs?configs;
?}?data;
};

enum?pinctrl_map_type?{
?PIN_MAP_TYPE_INVALID,
?//不需要任何配置,僅僅為了表示state的存在
?PIN_MAP_TYPE_DUMMY_STATE,
?//配置管腳復(fù)用
?PIN_MAP_TYPE_MUX_GROUP,
?//配置pin
?PIN_MAP_TYPE_CONFIGS_PIN,
?//配置pin?group
?PIN_MAP_TYPE_CONFIGS_GROUP,
};

struct?pinctrl_map_mux?{
?//group的名字
?const?char?*group;
?//function的名字
?const?char?*function;
};

struct?pinctrl_map_configs?{
?//該pin或者pin?group的名字
?const?char?*group_or_pin;
?//configuration數(shù)組
?unsigned?long?*configs;
?//配置項(xiàng)的個(gè)數(shù)
?unsigned?num_configs;
};

pinctrl driver 確定了 pin map 各個(gè)字段的格式之后,就可以在 dts 文件中維護(hù) pin state 以及相應(yīng)的 mapping table。pinctrl core 在初始化的時(shí)候,會(huì)讀取并解析 dts,并生成 pin map。

而各個(gè) consumer,可以在自己的 dts node 中,直接引用 pinctrl driver 定義的 pin state,并在設(shè)備驅(qū)動(dòng)的相應(yīng)的位置,調(diào)用 pinctrl subsystem 提供的 API(pinctrl_lookup_state,pinctrl_select_state),active 或者 deactive 這些 state。

pin controller 驅(qū)動(dòng)初始化

我們?cè)賮砘貞浵?pin 控制器的描述符:

struct?pinctrl_desc?{
?const?char?*name;
?const?struct?pinctrl_pin_desc?*pins;
?unsigned?int?npins;
?const?struct?pinctrl_ops?*pctlops;
?const?struct?pinmux_ops?*pmxops;
?const?struct?pinconf_ops?*confops;
?struct?module?*owner;
#ifdef?CONFIG_GENERIC_PINCONF
?unsigned?int?num_custom_params;
?const?struct?pinconf_generic_params?*custom_params;
?const?struct?pin_config_item?*custom_conf_items;
#endif
};

pin 控制器描述符中包括了三類操作函數(shù):pctlops 是一些全局的控制函數(shù);pmxops 是復(fù)用引腳相關(guān)的操作函數(shù);confops操作函數(shù)是用來配置引腳的特性。pin 控制器驅(qū)動(dòng)的初始化主要是注冊(cè)這三類函數(shù)的回調(diào)。

struct pinctrl_ops *pctlops

callback函數(shù) 描述
get_groups_count 該pin controller支持多少個(gè)pin group
get_group_name 給定一個(gè)selector(index),獲取指定pin group的name
get_group_pins 給定一個(gè)selector(index),獲取該pin group中pin的信息(該pin group包括多少個(gè)pin,每個(gè)pin的ID是什么)
pin_dbg_show debug fs的callback接口
dt_node_to_map 分析一個(gè)pin configuration node并把分析的結(jié)果保存成mapping table entry,每一個(gè)entry表示一個(gè)setting(一個(gè)功能復(fù)用設(shè)定,或者電氣特性設(shè)定)
dt_free_map 上面函數(shù)的逆函數(shù)

struct pinmux_ops *pmxops

callback函數(shù) 描述
get_functions_count 返回pin controller支持的function的數(shù)目
get_function_name 給定一個(gè)selector(index),獲取指定function的name
get_function_groups 給定一個(gè)selector(index),獲取指定function的pin groups信息
set_mux 將指定的pin group(group_selector)設(shè)置為指定的function(func_selector)

struct pinconf_ops *confops

callback函數(shù) 描述
pin_config_get 給定一個(gè)pin ID以及config type ID,獲取該引腳上指定type的配置
pin_config_set 設(shè)定一個(gè)指定pin的配置
pin_config_dbg_show debug接口
pin_config_group_dbg_show debug接口

pinctrl subsystem 的整體流程

pinctrl driver 根據(jù) pin controller 的實(shí)際情況,定義 struct pinctrl_desc(包括pin/pin group 的抽象,function 的抽象,pinconf、pinmux 的 operation API 實(shí)現(xiàn),dt_node_to_map 的實(shí)現(xiàn),等等),并注冊(cè)到 kernel 中。

pinctrl driver 在 pin controller的 dts node 中,根據(jù)自己定義的格式,描述每個(gè) device 的所有 pin state。如下所示:

&iomuxc1?{
?......
????pinctrl_lpuart5:?lpuart5grp?{
????????????fsl,pins?=?<
????????????????????MX8ULP_PAD_PTF14__LPUART5_TX????0x3
????????????????????MX8ULP_PAD_PTF15__LPUART5_RX????0x3
????????????>;
????};
?......
?pinctrl_usdhc0:?usdhc0grp?{
????????????fsl,pins?=?<
????????????????????MX8ULP_PAD_PTD1__SDHC0_CMD??????0x3
????????????????????MX8ULP_PAD_PTD2__SDHC0_CLK??????0x10002
????????????????????MX8ULP_PAD_PTD10__SDHC0_D0??????0x3
????????????????????MX8ULP_PAD_PTD9__SDHC0_D1???????0x3
????????????????????MX8ULP_PAD_PTD8__SDHC0_D2???????0x3
????????????????????MX8ULP_PAD_PTD7__SDHC0_D3???????0x3
????????????????????MX8ULP_PAD_PTD6__SDHC0_D4???????0x3
????????????????????MX8ULP_PAD_PTD5__SDHC0_D5???????0x3
????????????????????MX8ULP_PAD_PTD4__SDHC0_D6???????0x3
????????????????????MX8ULP_PAD_PTD3__SDHC0_D7???????0x3
????????????????????MX8ULP_PAD_PTD11__SDHC0_DQS?????0x10002
????????????>;
????};
?......
}
    相應(yīng)的 consumer driver 可以在自己的 dts node 中,引用 pinctrl driver 所定義的 pin state,如下所示:
&lpuart5?{
????????/*?console?*/
????????pinctrl-names?=?"default",?"sleep";
????????pinctrl-0?=?<&pinctrl_lpuart5>;
????????pinctrl-1?=?<&pinctrl_lpuart5>;
????????status?=?"okay";
};

&usdhc0?{
????????pinctrl-names?=?"default",?"state_100mhz",?"state_200mhz",?"sleep";
????????pinctrl-0?=?<&pinctrl_usdhc0>;
????????pinctrl-1?=?<&pinctrl_usdhc0>;
????????pinctrl-2?=?<&pinctrl_usdhc0>;
????????pinctrl-3?=?<&pinctrl_usdhc0>;
????????non-removable;
????????bus-width?=?<8>;
????????status?=?"okay";
};
    consumer driver 在需要的時(shí)候,可以調(diào)用 pinctrl_get/devm_pinctrl_get 接口,獲得一個(gè) pinctrl handle(struct pinctrl類型的指針)。在 pinctrl get 的過程中,解析 consumer device 的 dts node,找到相應(yīng)的 pin state,進(jìn)行調(diào)用 pinctrl driver 提供的 dt_node_to_map 接口,解析 pin state 并轉(zhuǎn)換為 pin map。

例子

上圖中,左邊是 pin controller 節(jié)點(diǎn),右邊是 client device 節(jié)點(diǎn) 。

    pin state

對(duì)于一個(gè)“client device”來說,比如對(duì)于一個(gè) UART 設(shè)備,它有多個(gè)“狀態(tài)”:default、sleep 等,那對(duì)應(yīng)的引腳也有這些狀態(tài)。比如當(dāng)這個(gè)設(shè)備處于 default 狀態(tài)時(shí),pinctrl 子系統(tǒng)會(huì)自動(dòng)根據(jù)上述信息把所用引腳復(fù)用為 uart0 功能。當(dāng)這這個(gè)設(shè)備處于 sleep 狀態(tài)時(shí),pinctrl 子系統(tǒng)會(huì)自動(dòng)根據(jù)上述信息把所用引腳配置為高電平。

    groups 和 function

一個(gè)設(shè)備會(huì)用到一個(gè)或多個(gè)引腳,這些引腳就可以歸為一組 group。這些引腳可以復(fù)用為某個(gè)功能 function。當(dāng)然,一個(gè)設(shè)備可以用到多組多功能引腳,比如A1、A2兩組引腳,A1組復(fù)用為F1功能,A2組復(fù)用為F2功能。

sysfs 訪問方法

gpio

數(shù)據(jù)結(jié)構(gòu)

每個(gè) GPIO 控制器用一個(gè) gpio_device 來表示:

struct?gpio_device?{
?//它是系統(tǒng)中第幾個(gè)GPIO控制器
?int???id;
?struct?device??dev;
?struct?cdev??chrdev;
?struct?device??*mockdev;
?struct?module??*owner;
?//含有各類操作函數(shù)
?struct?gpio_chip?*chip;
?//每一個(gè)gpio引腳用一個(gè)gpio_desc來表示
?struct?gpio_desc?*descs;
?//這些GPIO的號(hào)碼基值
?int???base;
?//這個(gè)GPIO控制器支持多少個(gè)GPIO
?u16???ngpio;
?//標(biāo)簽,名字
?char???*label;
?void???*data;
?struct?list_head????????list;
?......
};

用 gpio_chip 來定義控制引腳和中斷相關(guān)的函數(shù):

struct?gpio_chip?{
?const?char??*label;
?struct?gpio_device?*gpiodev;
?struct?device??*parent;
?struct?module??*owner;

?//控制引腳的函數(shù),中斷相關(guān)的函數(shù)
?int???(*request)(struct?gpio_chip?*chip,
??????unsigned?offset);
?void???(*free)(struct?gpio_chip?*chip,
??????unsigned?offset);
?int???(*get_direction)(struct?gpio_chip?*chip,
??????unsigned?offset);
?int???(*direction_input)(struct?gpio_chip?*chip,
??????unsigned?offset);
?int???(*direction_output)(struct?gpio_chip?*chip,
??????unsigned?offset,?int?value);
?int???(*get)(struct?gpio_chip?*chip,
??????unsigned?offset);
?void???(*set)(struct?gpio_chip?*chip,
??????unsigned?offset,?int?value);
?void???(*set_multiple)(struct?gpio_chip?*chip,
??????unsigned?long?*mask,
??????unsigned?long?*bits);
?int???(*set_config)(struct?gpio_chip?*chip,
???????????unsigned?offset,
???????????unsigned?long?config);
?int???(*to_irq)(struct?gpio_chip?*chip,
??????unsigned?offset);

?void???(*dbg_show)(struct?seq_file?*s,
??????struct?gpio_chip?*chip);
?//GPIO控制器中引腳的號(hào)碼基值
?int???base;
?//GPIO控制器中引腳的個(gè)數(shù)
?u16???ngpio;
?//每個(gè)引腳的名字
?const?char??*const?*names;
?bool???can_sleep;
?......
};

每一個(gè) gpio 引腳用一個(gè) gpio_desc 來表示:

struct?gpio_desc?{
?//屬于哪個(gè)?GPIO?控制器
?struct?gpio_device?*gdev;
?unsigned?long??flags;
/*?flag?symbols?are?bit?numbers?*/
#define?FLAG_REQUESTED?0
#define?FLAG_IS_OUT?1
#define?FLAG_EXPORT?2?/*?protected?by?sysfs_lock?*/
#define?FLAG_SYSFS?3?/*?exported?via?/sys/class/gpio/control?*/
#define?FLAG_ACTIVE_LOW?6?/*?value?has?active?low?*/
#define?FLAG_OPEN_DRAIN?7?/*?Gpio?is?open?drain?type?*/
#define?FLAG_OPEN_SOURCE?8?/*?Gpio?is?open?source?type?*/
#define?FLAG_USED_AS_IRQ?9?/*?GPIO?is?connected?to?an?IRQ?*/
#define?FLAG_IS_HOGGED?11?/*?GPIO?is?hogged?*/
#define?FLAG_SLEEP_MAY_LOOSE_VALUE?12?/*?GPIO?may?loose?value?in?sleep?*/

?/*?Connection?label?*/
?//一般等于?gpio_chip?的?label
?const?char??*label;
?/*?Name?of?the?GPIO?*/
?//引腳名
?const?char??*name;
};

設(shè)備樹

GPIO一般都分為幾組,每組中有若干個(gè)引腳。所以在使用GPIO子系統(tǒng)之前,就要先確定它所在的組以及在組中的哪一個(gè)。在設(shè)備樹中,“GPIO組” 就是一個(gè) GPIO Controller,這通常都由芯片廠家設(shè)置好。我們要做的是找到它的名字,比如“gpio1”,然后指定要用它里面的哪個(gè)引腳,比如 <&gpio1 0>。

“gpio-controller”表示這個(gè)節(jié)點(diǎn)是一個(gè)GPIO Controller,它下面有很多引腳。

“#gpio-cells = <2>”表示這個(gè)控制器下每一個(gè)引腳要用2個(gè)32位的數(shù)(cell)來描述。用第1個(gè)cell來表示哪一個(gè)引腳,用第2個(gè)cell來表示有效電平:GPIO_ACTIVE_HIGH(高電平有效),GPIO_ACTIVE_LOW(低電平有效)。

怎么引用某個(gè)引腳呢?在自己的設(shè)備節(jié)點(diǎn)中使用屬性"[name]-gpios",示例如下:

gpio controller 驅(qū)動(dòng)

gpio client 驅(qū)動(dòng)

GPIO 子系統(tǒng)有兩套接口:基于描述符的(descriptor-based)、老的(legacy)。前者的函數(shù)都有前綴 “gpiod_”,它使用 gpio_desc 結(jié)構(gòu)體來表示一個(gè)引腳;后者的函數(shù)都有前綴 “gpio_”,它使用一個(gè)整數(shù)來表示一個(gè)引腳。

要操作一個(gè)引腳,首先要 get 引腳,然后設(shè)置方向,讀值、寫值。

建議使用“devm_”版本的相關(guān)函數(shù)。有前綴“devm_”的含義是“設(shè)備資源管理”(Managed Device Resource),這是一種自動(dòng)釋放資源的機(jī)制。它的思想是“資源是屬于設(shè)備的,設(shè)備不存在時(shí)資源就可以自動(dòng)釋放”。

比如在 Linux 開發(fā)過程中,先申請(qǐng)了GPIO,再申請(qǐng)內(nèi)存;如果內(nèi)存申請(qǐng)失敗,那么在返回之前就需要先釋放GPIO資源。如果使用devm的相關(guān)函數(shù),在內(nèi)存申請(qǐng)失敗時(shí)可以直接返回:設(shè)備的銷毀函數(shù)會(huì)自動(dòng)地釋放已經(jīng)申請(qǐng)了的GPIO資源。

以上面的設(shè)備 max9286_mipi 為例,它的驅(qū)動(dòng)實(shí)現(xiàn)如下:

sysfs 訪問方法

先確定某個(gè)GPIO Controller的基準(zhǔn)引腳號(hào)(base number),再計(jì)算出某個(gè)引腳的號(hào)碼。

然后進(jìn)入某個(gè)gpiochip目錄,查看文件label的內(nèi)容,根據(jù) label 的內(nèi)容對(duì)比設(shè)備樹,就可以知道這對(duì)應(yīng)哪一個(gè) GPIO Controller。比如用上面的例子,通過對(duì)比設(shè)備樹可知 gpiochip448 對(duì)應(yīng) gpio1。

因?yàn)?pin number = base + offset,所以 GPIO1_27 的號(hào)碼是 448 + 27 = 475,那么通過 sys 可以做如下操作。

echo 475 > /sys/class/gpio/export

echo in > /sys/class/gpio/gpio475/direction

cat /sys/class/gpio/gpio475/value

echo 475 > /sys/class/gpio/unexport

pinctrl subsystem 和 gpio subsysem 之間的耦合

pinctrl subsystem 管理系統(tǒng)的所有管腳,GPIO 是這些管腳的用途之一,因此 gpio subsystem 應(yīng)該是 pinctrl subsystem 的 backend。在使用 GPIO 的時(shí)候,都需要向系統(tǒng)的 pinctrl subsystem 申請(qǐng)管腳,并將管腳配置為 GPIO 功能。

內(nèi)核也提供了通過 pinctrl 控制 gpio 的接口:

static inline int pinctrl_request_gpio(unsigned gpio);

static inline void pinctrl_free_gpio(unsigned gpio);

static inline int pinctrl_gpio_direction_input(unsigned gpio);

static inline int pinctrl_gpio_direction_output(unsigned gpio);

pinctrl subsystem會(huì)維護(hù)一個(gè)gpio number到pin number的map(gpio range),將gpio subsystem傳來的gpio number轉(zhuǎn)換為pin number之后,調(diào)用struct pinmux_ops中有關(guān)的回調(diào)函數(shù)即可:

struct?pinmux_ops?{
????????...
????????int?(*gpio_request_enable)?(struct?pinctrl_dev?*pctldev,
?????????????????????????????????????struct?pinctrl_gpio_range?*range,
?????????????????????????????????????unsigned?offset);
????????void?(*gpio_disable_free)?(struct?pinctrl_dev?*pctldev,
????????????????????????????????????struct?pinctrl_gpio_range?*range,
????????????????????????????????????unsigned?offset);
????????int?(*gpio_set_direction)?(struct?pinctrl_dev?*pctldev,
????????????????????????????????????struct?pinctrl_gpio_range?*range,
????????????????????????????????????unsigned?offset,
????????????????????????????????????bool?input);
};

gpio ranges

當(dāng) gpio driver 需要使用某一個(gè) gpio 的時(shí)候,可以在 struct gpio_chip 的 request 函數(shù)中,調(diào)用 pinctrl core 提供的 pinctrl_request_gpio 接口(參數(shù)是gpio編號(hào)),然后 pinctrl core 會(huì)查尋 gpio ranges 鏈表,將 gpio 編號(hào)轉(zhuǎn)換成 pin 編號(hào),然后調(diào)用 pinctrl 的相應(yīng)接口(參數(shù)是pin編號(hào)),申請(qǐng)?jiān)?pin 的使用。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

針對(duì)嵌入式人工智能,物聯(lián)網(wǎng)等專業(yè)技術(shù)分享和交流平臺(tái),內(nèi)容涉及arm,linux,android等各方面。

Arm64 ?;厮?>
				</a>
							</li>
						<li id=
  • Linux BSP實(shí)戰(zhàn)課(中斷篇):中斷控制器的驅(qū)動(dòng)實(shí)現(xiàn)
  • 查看更多