自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

GPIO到底該如何控制

原創(chuàng) 精選
系統(tǒng) Linux
希望大家通過本文,可以了解內(nèi)核中GPIO的機(jī)制并掌握其操作方法,但需要說明的是在內(nèi)核之前的階段也會(huì)進(jìn)行引腳的配置,比如我們使用串口來打印bootloader階段的日志,這種情況下串口引腳一定是在內(nèi)核之前的階段進(jìn)行配置的。

作者 | 趙青窕

隨著Linux內(nèi)核代碼的逐步完善,其GPIO口的操作接口也在不斷完善。內(nèi)核中存在多種GPIO API接口,我們?cè)撊绾问褂眠@些API接口呢?我們又該如何在設(shè)備樹中配置GPIO呢?

目前的內(nèi)核中提供了三種版本的API接口供我們使用,分別是Pinctrl子系統(tǒng)對(duì)應(yīng)的API接口和GPIO子系統(tǒng)對(duì)應(yīng)的API接口(GPIO子系統(tǒng)提供了兩種類型的API接口),在本文中我將會(huì)通過內(nèi)核中GPIO架構(gòu)的角度來說明這三類API接口;我們對(duì)GPIO的控制,除了合適的API接口外,還需要通過設(shè)備樹對(duì)GPIO進(jìn)行配置,雖然不同架構(gòu)中設(shè)備樹的配置方式不同,但本文中也會(huì)舉例說明設(shè)備樹如何配置,對(duì)應(yīng)的代碼中如何使用API接口;最后說明我們可以用到的調(diào)試手段。

1.內(nèi)核GPIO架構(gòu)

下圖是內(nèi)核中,GPIO架構(gòu)中的核心部分框架圖(暫時(shí)不考慮GPIO架構(gòu)對(duì)應(yīng)的sysfs和debugfs):

圖 1:GPIO架構(gòu)

從上圖中的上半部分可以看出以下關(guān)鍵信息:

  • 內(nèi)核提供了兩種控制引腳的方式,一種是采用Pinctrl子系統(tǒng),一種是采用GPIO子系統(tǒng)(該系統(tǒng)又有兩種方式,后面小節(jié)中會(huì)進(jìn)行說明),用戶編寫驅(qū)動(dòng)時(shí)可以調(diào)用這兩個(gè)子系統(tǒng)提供的API接口來達(dá)到控制GPIO口的目的;
  • GPIO子系統(tǒng)的功能是通過Pinctrl子系統(tǒng)來實(shí)現(xiàn)的。雖然從圖中看出,Pinctrl子系統(tǒng)和GPIO子系統(tǒng)并存,但內(nèi)核需要對(duì)所有的GPIO口進(jìn)行管理,因此就需要一個(gè)統(tǒng)一的管理接口或者模塊,Pinctrl就完成這種統(tǒng)一管理的目標(biāo),比如我們采用GPIO子系統(tǒng)的API接口gpio_request來申請(qǐng)GPIO口時(shí),內(nèi)核需要記錄哪些GPIO口已經(jīng)申請(qǐng)過了,若Pinctrl子系統(tǒng)和GPIO子系統(tǒng)各維護(hù)一套GPIO管理策略,那就可能導(dǎo)致Pinctrl子系統(tǒng)和GPIO子系統(tǒng)同時(shí)操作同一個(gè)GPIO口的情況,這種顯然是不可行的,且從高通平臺(tái)內(nèi)核代碼中可以看出gpio_request有如下的調(diào)用關(guān)系:

gpio_request--->gpiod_request----> gpiod_request_commit---->chip->request(系統(tǒng)啟動(dòng)時(shí)設(shè)置為gpopchip_generic_request) ---->pinctrl_gpio_request

該調(diào)用關(guān)系從GPIO子系統(tǒng)的API函數(shù)gpio_request最后調(diào)用了Pinctrl子系統(tǒng)的函數(shù)pinctrl_gpio_request,這種調(diào)用關(guān)系,也證實(shí)了Pinctrl和GPIO子系統(tǒng)的關(guān)系。對(duì)于其他接口,如gpio_direction_input,gpio_set_value等函數(shù)的調(diào)用,同gpio_request相似,其最后均是調(diào)用到對(duì)應(yīng)的chip->direction_input,chip->set,進(jìn)而調(diào)用pinctrl_gpio_direction_input,等函數(shù),由于這類API函數(shù)比較多,在此就不展示其調(diào)用關(guān)系了;

  • 內(nèi)核采用結(jié)構(gòu)體struct pinctrl_dev來表示一個(gè)控制器,所有的pinctrl_dev會(huì)形成鏈表,鏈表頭就是pinctrldev_list,在函數(shù)pinctrl_gpio_request內(nèi)部,會(huì)調(diào)用函數(shù)pinctrl_get_device_gpio_range來根據(jù)GPIO號(hào),遍歷鏈表pinctrldev_list來查找該GPIO口對(duì)應(yīng)的pinctrl_dev,當(dāng)然這部分工作均是由系統(tǒng)來維護(hù),我們只需知道整個(gè)框架,并如何使用GPIO的整個(gè)子系統(tǒng)即可。

注意:目前從我看到的代碼中發(fā)現(xiàn),有些廠家在實(shí)現(xiàn)GPIO子系統(tǒng)時(shí),并非所有的功能均通過Pinctrl子系統(tǒng),但gpio_request是會(huì)通過Pinctrl子系統(tǒng),因?yàn)镻inctrl子系統(tǒng)中會(huì)標(biāo)記哪些GPIO已經(jīng)request了,這樣后續(xù)模塊采用request繼續(xù)申請(qǐng)?jiān)撡Y源時(shí)就會(huì)失敗;不過大家放心,即使其部分功能不通過Pinctrl子系統(tǒng),但其對(duì)驅(qū)動(dòng)模塊提供的API接口不受其影響。

2.用戶驅(qū)動(dòng)中控制GPIO

在編寫驅(qū)動(dòng)時(shí),可以采用以下兩種方式來設(shè)置:

  • Pinctrl方式,該方式最終是采用Pinctrl子系統(tǒng)來實(shí)現(xiàn)各項(xiàng)功能的;
  • 采用GPIO子系統(tǒng)接口的方式,該方式其實(shí)有兩種,分別是legacy和gpio description的方式。但目前的內(nèi)核中,legacy內(nèi)部會(huì)調(diào)用gpio description的方式,后面內(nèi)容中,我會(huì)以legacy的方式來說明使用方法。

Pinctrl控制引腳方式

下面,我以高通平臺(tái)Pinctrl的方式來說明其代碼和設(shè)備樹的配置。

我們先來看一下設(shè)備樹:

&tlmm{
client1_state1: client1_state1 {
mux {
pins = "gpio0";
function = "gpio";
};
config {
pins = "gpio0";
bias-disable;
drive-strength =<2> ;
input-enable;
};
};
client1_state2: client1_state2 {
mux {
pins = "gpio0";
function = "gpio";
};
config {
pins = "gpio0";
bias-disable;
drive-strength = <2>;
output-high;
};
};
};

&soc {
client1 {
pinctrl-names = "state1", "state2";
pinctrl-0 = <&client1_state1 >;
pinctrl-1 = <&client1_state2>;
};
};

上面是典型的設(shè)備樹的配置,其中包含兩個(gè)節(jié)點(diǎn),分別是tlmm中的引腳配置和我們的設(shè)備client1。

tlmm中定義了兩種GPIO狀態(tài),分別是作為輸入功能的GPIO0和作為輸出功能的GPIO0。不同平臺(tái)的設(shè)備樹中的配置方法不同,但均需要像上面設(shè)備樹那樣,配置兩部分:

引腳功能配置,是作為普通的GPIO口,還是復(fù)用為其他的功能;

引腳驅(qū)動(dòng)配置,包括引腳內(nèi)部的上拉或者下拉,驅(qū)動(dòng)能力等。

接下來,一起看下代碼中如何進(jìn)行操作,其操作需要按照下面的順序:

  • 先調(diào)用devm_pinctrl_get或者pinctrl_get函數(shù)獲取對(duì)應(yīng)的struct pinctrl*;
  • 緊接著調(diào)用pinctrl_lookup_state(struct pinctrl *p, const char *name)來根據(jù)name獲取對(duì)應(yīng)的配置;
  • 最后我們采用函數(shù)pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)來進(jìn)行狀態(tài)的選擇。選擇某一狀態(tài),就是設(shè)置了對(duì)應(yīng)的引腳,且引腳的request操作是在該函數(shù)內(nèi)部完成的,該函數(shù)內(nèi)部會(huì)調(diào)用pin_request來進(jìn)行申請(qǐng),且調(diào)用該函數(shù)后,引腳的狀態(tài)就是設(shè)備樹中設(shè)備的狀態(tài),如上面設(shè)備樹中,client1_state1對(duì)應(yīng)的引腳使用了其GPIO功能,且配置為輸入(設(shè)備樹中是通過input-enable進(jìn)行配置的),client1_state2對(duì)應(yīng)的引腳也使用了其GPIO的功能,且配置為輸出高(設(shè)備樹中是通過out-high進(jìn)行配置的)。

采用GPIO子系統(tǒng)


&soc {
client1 {
qcom,gpio-client1 = <&tlmm 100 0>; //100就是GPIO號(hào)
}

這種方式在設(shè)備樹的配置方式上比較簡(jiǎn)單,其代碼操作如下:

  • 使用函數(shù)of_get_named_gpio(node, " qcom,gpio-client1", 0)獲取GPIO號(hào)。
  • 接下來是最重要的一步,調(diào)用函數(shù)gpio_request來進(jìn)行GPIO的request操作。該函數(shù)最后會(huì)通過Pinctrl接口間接調(diào)用pin_request來進(jìn)行引腳的申請(qǐng)操作。之前有一次工作中粗心,忘記request操作,但發(fā)現(xiàn)該GPIO可能也會(huì)正常操作,但會(huì)有工作不穩(wěn)定的情況發(fā)生;
  • 接下來可以調(diào)用函數(shù)gpio_direction_input或者gpio_direction_output來進(jìn)行GPIO輸入或者輸出模式的配置,gpio_direction_output調(diào)用的同時(shí),可以設(shè)置輸出高或者輸出低;
  • 如果配置位輸入模式,則可以使用函數(shù)gpio_get_value來獲取GPIO口的狀態(tài)。

如果需要把引腳配置為中斷功能,則我們需要使用函數(shù)irq = gpio_to_irq(gpio)來獲得irq號(hào),根據(jù)irq號(hào)來進(jìn)行適當(dāng)?shù)闹袛嗯渲谩?/p>

通過上面兩種方式,我們可以發(fā)現(xiàn)Pinctrl的方式,其設(shè)備樹復(fù)雜,但API接口簡(jiǎn)單,只需要通過函數(shù)pinctrl_select_state選擇設(shè)備樹中某一配置即可。GPIO子系統(tǒng)的方式是設(shè)備樹簡(jiǎn)單,但代碼復(fù)雜,設(shè)備樹中只配置了GPIO號(hào),其余的如GPIO的方向及輸出信號(hào)均需要通過代碼來進(jìn)行設(shè)置,這正是不同API接口及其設(shè)備樹的優(yōu)缺點(diǎn)。

3.GPIO調(diào)試

不同平臺(tái)的調(diào)試方式可能會(huì)存在一些差異,比如MTK的不同平臺(tái)間都會(huì)有差異,在此我就介紹一種常見的需要debugfs支持的方式。

我們?cè)诰幾g內(nèi)核時(shí),需要配置相應(yīng)的debugfs宏來打開該功能,只有配置相應(yīng)宏后,我們就可以進(jìn)入機(jī)器的/sys/class/gpio下對(duì)GPIO口進(jìn)行操作,下面是對(duì)應(yīng)的操作順序:

  • cd /sys/class/gpio/
  • echo 99 > export(此處99代表引腳號(hào),確切地說echo時(shí),應(yīng)采用對(duì)應(yīng)引腳gpio_request獲得到的數(shù)值)
  • cd gpio99
  • echo in/out > direction //設(shè)置GPIO輸入或輸出
  • cat direction //獲取GPIO輸入輸出狀態(tài)
  • echo 0/1 > value //拉低或者拉高對(duì)應(yīng)的GPIO口
  • cat value //查看GPIO口的高低狀態(tài)

4.總結(jié)

希望大家通過本文,可以了解內(nèi)核中GPIO的機(jī)制并掌握其操作方法,但需要說明的是在內(nèi)核之前的階段也會(huì)進(jìn)行引腳的配置,比如我們使用串口來打印bootloader階段的日志,這種情況下串口引腳一定是在內(nèi)核之前的階段進(jìn)行配置的。

作者介紹

趙青窕,51CTO社區(qū)編輯,從事多年驅(qū)動(dòng)開發(fā)。研究興趣包含安全OS和網(wǎng)絡(luò)安全領(lǐng)域,發(fā)表過網(wǎng)絡(luò)相關(guān)專利。

責(zé)任編輯:武曉燕 來源: 51CTO技術(shù)棧
相關(guān)推薦

2021-01-15 19:10:32

日志打印原則

2021-07-08 21:51:03

5G技術(shù)Wi-Fi 6

2022-06-14 21:14:18

5.5GAI數(shù)字化

2024-01-25 18:00:56

微服務(wù)系統(tǒng)KafkaRabbitMQ

2019-08-20 09:16:39

6G網(wǎng)絡(luò)1G

2022-02-23 21:08:53

數(shù)字4G5G

2020-07-14 14:40:05

激光噴墨打印

2015-06-02 11:26:29

產(chǎn)品團(tuán)隊(duì)

2011-07-28 20:32:51

2011-07-29 10:51:26

2020-06-02 14:40:42

5G邊緣計(jì)算物聯(lián)網(wǎng)

2025-03-31 08:04:50

MySQLCPU內(nèi)存

2020-12-30 09:00:00

安全工具攻擊

2009-04-24 08:26:02

Mobile Mark移動(dòng)OS

2017-01-06 14:57:02

2017-04-05 21:43:08

MQ互聯(lián)網(wǎng)架構(gòu)

2021-07-19 18:05:46

網(wǎng)絡(luò)安全APT攻擊網(wǎng)絡(luò)攻擊

2023-03-15 08:42:06

form表單設(shè)計(jì)接口

2021-08-19 14:00:13

人工智能AI自動(dòng)駕駛
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)