精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux GPIO開發(fā)指南

嵌入式Linux那些事 ? 來源:嵌入式Linux那些事 ? 作者:嵌入式Linux那些事 ? 2023-03-06 10:20 ? 次閱讀

Linux GPIO 開發(fā)指南

1 概述

1.1 編寫目的

本文檔對內核的 GPIO 接口使用進行詳細的闡述,讓用戶明確掌握 GPIO 配置、申請等操作的編程方法。

1.2 適用范圍

表 1-1: 適用產品列表

內核版本 驅動文件
Linux-4.9 及以上 pinctrl-sunxi.c

1.3 相關人員

本文檔適用于所有需要在 Linux 內核 sunxi 平臺上開發(fā)設備驅動的相關人員。

2 模塊介紹

Pinctrl 框架是 linux 系統(tǒng)為統(tǒng)一各 SoC 廠商 pin 管理,避免各 SoC 廠商各自實現(xiàn)相同 pin 管理子系統(tǒng)而提出的。目的是為了減少 SoC 廠商系統(tǒng)移植工作量。

2.1 模塊功能介紹

許多 SoC 內部都包含 pin 控制器,通過 pin 控制器,我們可以配置一個或一組引腳的功能和特性。在軟件上,Linux 內核 pinctrl 驅動可以操作 pin 控制器為我們完成如下工作:

? 枚舉并且命名 pin 控制器可控制的所有引腳;

? 提供引腳的復用能力

? 提供配置引腳的能力,如驅動能力、上拉下拉、數(shù)據屬性等。

? 與 gpio 子系統(tǒng)的交互

? 實現(xiàn) pin 中斷

2.2 相關術語介紹

表 2-1: Pinctrl 模塊相關術語介紹

術語 解釋說明
SUNXI Allwinner 一系列 SOC 硬件平臺
Pin controller 是對硬件模塊的軟件抽象,通常用來表示硬件控制器。能夠處理引腳復用、屬性配置等功能
Pin 根據芯片不同的封裝方式,可以表現(xiàn)為球形、針型等。軟件上采用常用一組無符號的整數(shù) [0-maxpin] 來表示
Pin groups 外圍設備通常都不只一個引腳,比如 SPI,假設接在 SoC 的 {0,8,16,24} 管腳,而另一個設備 I2C 接在 SoC 的 {24,25} 管腳。我們可以說這里有兩個pin groups。很多控制器都需要處理 pin groups。因此管腳控制器子系統(tǒng)需要一個機制用來枚舉管腳組且檢索一個特定組中實際枚舉的管腳
Pinconfig 管腳可以被軟件配置成多種方式,多數(shù)與它們作為輸入/輸出時的電氣特性相關。例如,可以設置一個輸出管腳處于高阻狀態(tài),或是 “三態(tài)”(意味著它被有效地斷開連接)?;蛘呖梢酝ㄟ^設置將一個輸入管腳與 VDD 或 GND 相連 (上拉/下拉),以便在沒有信號驅動管腳時使管腳擁有確認值
Pinmux 引腳復用功能,使用一個特定的物理管腳(ball/pad/finger/等等)進行多種擴展復用,以支持不同功能的電氣封裝習慣
Device tree 猶如它的名字,是一棵包括 cpu 的數(shù)量和類別、內存基地址、總線與橋、外設連接,中斷控制器和 gpio 以及 clock 等系統(tǒng)資源的樹,Pinctrl 驅動支持從device tree 中定義的設備節(jié)點獲取 pin 的配置信息

2.3 總體框架

Sunxi Pinctrl 驅動模塊的框架如下圖所示,整個驅動模塊可以分成 4 個部分:pinctrl api、pinctrl common frame、sunxi pinctrl driver,以及 board configuration。(圖中最上面一層 device driver 表示 Pinctrl 驅動的使用者)

poYBAGQFTdiAWyaaAAE1fP-4vMw306.png

圖 2-1: pinctrl 驅動整體框架圖

Pinctrl api: pinctrl 提供給上層用戶調用的接口。

Pinctrl framework:Linux 提供的 pinctrl 驅動框架。

Pinctrl sunxi driver:sunxi 平臺需要實現(xiàn)的驅動。

Board configuration:設備 pin 配置信息,一般采用設備樹進行配置。

2.4 state/pinmux/pinconfig

Pinctrl framework 主要處理 pinstate、pinmux 和 pinconfig 三個功能,pinstate 和 pinmux、pinconfig 映射關系如下圖所示。

pYYBAGQFTdmAZA7bAAD22YrKq0I009.png

圖 2-2: pinctrl 驅動 framework 圖

系統(tǒng)運行在不同的狀態(tài),pin 配置有可能不一樣,比如系統(tǒng)正常運行時,設備的 pin 需要一組配置,但系統(tǒng)進入休眠時,為了節(jié)省功耗,設備 pin 需要另一組配置。Pinctrl framwork 能夠有效管理設備在不同狀態(tài)下的引腳配置。

2.5 源碼結構介紹

linux

|

|-- drivers

| |-- pinctrl

| | |-- Kconfig

| | |-- Makefile

| | |-- core.c

| | |-- core.h

| | |-- devicetree.c

| | |-- devicetree.h

| | |-- pinconf.c

| | |-- pinconf.h

| | |-- pinmux.c

| | `-- pinmux.h

| `-- sunxi

| |-- pinctrl-sunxi-test.c

| |-- pinctrl-sun*.c

| `-- pinctrl-sun*-r.c

`-- include

`-- linux

`-- pinctrl

|-- consumer.h

|-- devinfo.h

|-- machine.h

|-- pinconf-generic.h

|-- pinconf.h

|-- pinctrl-state.h

|-- pinctrl.h

`-- pinmux.h

3 模塊配置

3.1 kernel menuconfig 配置

進入 longan 根目錄,執(zhí)行./build.sh menuconfig

進入配置主界面,并按以下步驟操作:

首先,選擇 Device Drivers 選項進入下一級配置,如下圖所示:

poYBAGQFTdqAKSdCAAG-HhaAL5I681.png

圖 3-1: 內核 menuconfig 根菜單

選擇 Pin controllers, 進入下級配置,如下圖所示:

pYYBAGQFTdqACepeAAJpsTfRs_E744.png

圖 3-2: 內核 menuconfig device drivers 菜單

選擇 Allwinner SoC PINCTRL DRIVER, 進入下級配置,如下圖所示:

poYBAGQFTduAN2FkAACaI37pQiM341.png

圖 3-3: 內核 menuconfig pinctrl drivers 菜單

Sunxi pinctrl driver 默認編譯進內核,如下圖(以 sun50iw9p1 平臺為例,其他平臺類似)所示:

poYBAGQFTdyAJPa8AACemI2-XEU596.png

圖 3-4: 內核 menuconfig allwinner pinctrl drivers 菜單

3.2 device tree 源碼結構和路徑

對于 Linux4.9:

? 設備樹文件的配置是該 SoC 所有方案的通用配置,對于 ARM64 CPU 而言,設備樹的路徑為:kernel/{KERNEL}/arch/arm64/boot/dts/sunxi/sun*-pinctrl.dtsi。

? 設備樹文件的配置是該 SoC 所有方案的通用配置,對于 ARM32 CPU 而言,設備樹的路徑為:kernel/{KERNEL}/arch/arm32/boot/dts/sun*-pinctrl.dtsi。

? 板級設備樹 (board.dts) 路徑:/device/config/chips/{IC}/configs/{BOARD}/board.dts

device tree 的源碼結構關系如下:

board.dts

|--------sun*.dtsi

|------sun*-pinctrl.dtsi

|------sun*-clk.dtsi

對于 Linux5.4:

? 設備樹文件的配置是該 SoC 所有方案的通用配置,對于 ARM64 CPU 而言,5.4 內核中不再維護單獨的 pinctrl 的 dtsi,直接將 pin 的信息放在了:kernel/{KERNEL}/arch/arm32/boot/dts/sun*.dtsi

? 設備樹文件的配置是該 SoC 所有方案的通用配置,對于 ARM32 CPU 而言,5.4 內核中不再維護單獨的 pinctrl 的 dtsi,直接將 pin 的信息放在了:kernel/{KERNEL}/arch/arm32/boot/dts/sun*.dtsi

? 板級設備樹 (board.dts) 路徑:/device/config/chips/{IC}/configs/{BOARD}/board.dts

? device tree 的源碼包含關系如下:

board.dts

|--------sun*.dtsi

3.2.1 device tree 對 gpio 控制器的通用配置

在 kernel/{KERNEL}/arch/arm64/boot/dts/sunxi/sun-pinctrl.dtsi 文件中 (Linux5.4 直接放在 sun.dtsi 中),配置了該 SoC 的 pinctrl 控制器的通用配置信息,一般不建議修改,有 pinctrl 驅動維護者維護。目前,在 sunxi 平臺,我們根據電源域,注冊兩個 pinctrl 設備:r_pio 設 備 (PL0 后的所有 pin) 和 pio 設備 (PL0 前的所有 pin),兩個設備的通用配置信息如下:

r_pio: pinctrl@07022000 {

compatible = "allwinner,sun50iw9p1-r-pinctrl"; //兼容屬性,用于驅動和設備綁定

reg = <0x0 0x07022000 0x0 0x400>; //寄存器基地址0x07022000和范圍0x400

clocks = <&clk_cpurpio>; //r_pio設置使用的時鐘

device_type = "r_pio"; //設備類型屬性

gpio-controller; //表示是一個gpio控制器

interrupt-controller; //表示一個中斷控制器,不支持中斷可以刪除

#interrupt-cells = <3>; //pin中斷屬性需要配置的參數(shù)個數(shù),不支持中斷可以刪除

#size-cells = <0>; //沒有使用,配置0

#gpio-cells = <6>; //gpio屬性配置需要的參數(shù)個數(shù),對于linux-5.4為3

?

/*

* 以下配置為模塊使用的pin的配置,模塊通過引用相應的節(jié)點對pin進行操作

* 由于不同板級的pin經常改變,建議通過板級dts修改(參考下一小節(jié))

*/

s_rsb0_pins_a: s_rsb0@0 {

allwinner,pins = "PL0", "PL1";

allwinner,function = "s_rsb0";

allwinner,muxsel = <2>;

allwinner,drive = <2>;

allwinner,pull = <1>;

};

?

/*

* 以下配置為linux-5.4模塊使用pin的配置,模塊通過引用相應的節(jié)點對pin進行操作

* 由于不同板級的pin經常改變,建議將模塊pin的引用放到board dts中

*(類似pinctrl-0 = <&scr1_ph_pins>;),并使用scr1_ph_pins這種更有標識性的名字)。

*/

scr1_ph_pins: scr1-ph-pins {

pins = "PH0", "PH1";

function = "sim1";

drive-strength = <10>;

bias-pull-up;

};

};

?

pio: pinctrl@0300b000 {

compatible = "allwinner,sun50iw9p1-pinctrl"; //兼容屬性,用于驅動和設備綁定

reg = <0x0 0x0300b000 0x0 0x400>; //寄存器基地址0x0300b000和范圍0x400

interrupts = , /* AW1823_GIC_Spec: GPIOA: 83-32=51 */

,

,

,

,

,

; //該設備每個bank支持的中斷配置和gic中斷號,每個中斷號對應一個支持中斷的bank

device_type = "pio"; //設備類型屬性

clocks = <&clk_pio>, <&clk_losc>, <&clk_hosc>; //該設備使用的時鐘

gpio-controller; //表示是一個gpio控制器

interrupt-controller; //表示是一個中斷控制器

#interrupt-cells = <3>; //pin中斷屬性需要配置的參數(shù)個數(shù),不支持中斷可以刪除

#size-cells = <0>; //沒有使用

#gpio-cells = <6>; //gpio屬性需要配置的參數(shù)個數(shù),對于linux-5.4為3

/* takes the debounce time in usec as argument */

}

3.2.2 board.dts 板級配置

board.dts 用于保存每個板級平臺的設備信息 (如 demo 板、demo2.0 板等等),以 demo 板為例,board.dts 路徑如下:

/device/config/chips/{CHIP}/configs/demo/board.dts

在 board.dts 中的配置信息如果在 *.dtsi 中 (如 sun50iw9p1.dtsi 等) 存在,則會存在以下覆蓋規(guī)則:

? 相同屬性和結點,board.dts 的配置信息會覆蓋 *.dtsi 中的配置信息。

? 新增加的屬性和結點,會追加到最終生成的 dtb 文件中。

linux-4.9 上面 pinctrl 中一些模塊使用 board.dts 的簡單配置如下:

pio: pinctrl@0300b000 {

input-debounce = <0 0 0 0 0 0 0>; /*配置中斷采樣頻率,每個對應一個支持中斷的bank,單位us*/

spi0_pins_a: spi0@0 {

allwinner,pins = "PC0", "PC2", "PC4";

allwinner,pname = "spi0_sclk", "spi0_mosi", "spi0_miso";

allwinner,function = "spi0";

};

};

對于 linux-5.4,不建議采用上面的覆蓋方式,而是修改驅動 pinctrl-0 引用的節(jié)點。

linux-5.4 上面 board.dts 的配置如下:

&pio{

input-debounce = <0 0 0 0 1 0 0 0 0>; //配置中斷采樣頻率,每個對應一個支持中斷的bank,單位us

vcc-pe-supply = ; //配置IO口耐壓值,例如這里的含義是將pe口設置成1.8v耐壓值

};

4 模塊接口說明

4.1 pinctrl 接口說明

4.1.1 pin4ctrl_get

? 函數(shù)原型:struct pinctrl *pinctrl_get(struct device *dev);

? 作用:獲取設備的 pin 操作句柄,所有 pin 操作必須基于此 pinctrl 句柄。

? 參數(shù):

dev: 指向申請 pin 操作句柄的設備句柄。

? 返回:

成功,返回 pinctrl 句柄。

失敗,返回 NULL。

4.1.2 pinctrl_put

? 函數(shù)原型:void pinctrl_put(struct pinctrl *p)

? 作用:釋放 pinctrl 句柄,必須與 pinctrl_get 配對使用。

? 參數(shù):

? p: 指向釋放的 pinctrl 句柄。

? 返回:

? 沒有返回值。

! 警告

必須與 pinctrl_get 配對使用。

4.1.3 devm_pinctrl_get

? 函數(shù)原型:struct pinctrl *devm_pinctrl_get(struct device *dev)

? 作用:根據設備獲取 pin 操作句柄,所有 pin 操作必須基于此 pinctrl 句柄,與 pinctrl_get功能完全一樣,只是 devm_pinctrl_get 會將申請到的 pinctrl 句柄做記錄,綁定到設備句柄信息中。設備驅動申請 pin 資源,推薦優(yōu)先使用 devm_pinctrl_get 接口。

? 參數(shù):

? dev: 指向申請 pin 操作句柄的設備句柄。

? 返回:

? 成功,返回 pinctrl 句柄。

? 失敗,返回 NULL。

4.1.4 devm_pinctrl_put

? 函數(shù)原型:void devm_pinctrl_put(struct pinctrl *p)

? 作用:釋放 pinctrl 句柄,必須與 devm_pinctrl_get 配對使用。

? 參數(shù):

? p: 指向釋放的 pinctrl 句柄。

? 返回:

? 沒有返回值。

! 警告

必須與 devm_pinctrl_get 配對使用,可以不顯式的調用該接口。

4.1.5 pinctrl_lookup_state

? 函數(shù)原型:struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name)

? 作用:根據 pin 操作句柄,查找 state 狀態(tài)句柄。

? 參數(shù):

? p: 指向要操作的 pinctrl 句柄。

? name: 指向狀態(tài)名稱,如 “default”、“sleep” 等。

? 返回:

? 成功,返回執(zhí)行 pin 狀態(tài)的句柄 struct pinctrl_state *。

? 失敗,返回 NULL。

4.1.6 pinctrl_select_state

? 函數(shù)原型:int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s)

? 作用:將 pin 句柄對應的 pinctrl 設置為 state 句柄對應的狀態(tài)。

? 參數(shù):

? p: 指向要操作的 pinctrl 句柄。

? s: 指向 state 句柄。

? 返回:

? 成功,返回 0。

? 失敗,返回錯誤碼。

4.1.7 devm_pinctrl_get_select

? 函數(shù)原型:struct pinctrl *devm_pinctrl_get_select(struct device *dev, const char *name)

? 作用:獲取設備的 pin 操作句柄,并將句柄設定為指定狀態(tài)。

? 參數(shù):

? dev: 指向管理 pin 操作句柄的設備句柄。

? name: 要設置的 state 名稱,如 “default”、“sleep” 等。

? 返回:

? 成功,返回 pinctrl 句柄。

? 失敗,返回 NULL。

4.1.8 devm_pinctrl_get_select_default

? 函數(shù)原型:struct pinctrl *devm_pinctrl_get_select_default(struct device *dev)

? 作用:獲取設備的 pin 操作句柄,并將句柄設定為默認狀態(tài)。

? 參數(shù):

? dev: 指向管理 pin 操作句柄的設備句柄。

? 返回:

? 成功,返回 pinctrl 句柄。

? 失敗,返回 NULL。

4.1.9 pin_config_get

? 作用:獲取指定 pin 的屬性。

? 參數(shù):

? dev_name: 指向 pinctrl 設備。

? name: 指向 pin 名稱。

? config: 保存 pin 的配置信息。

? 返回:

? 成功,返回 pin 編號。

? 失敗,返回錯誤碼。

! 警告

該接口在 linux-5.4 已經移除。

4.1.10 pin_config_set

? 作用:設置指定 pin 的屬性。

? 參數(shù):

? dev_name: 指向 pinctrl 設備。

? name: 指向 pin 名稱。

? config:pin 的配置信息。

? 返回:

? 成功,返回 0。

? 失敗,返回錯誤碼。

! 警告

該接口在 linux-5.4 已經移除。

4.2 gpio 接口說明

4.2.1 gpio_request

? 函數(shù)原型:int gpio_request(unsigned gpio, const char *label)

? 作用:申請 gpio,獲取 gpio 的訪問權。

? 參數(shù):

? gpio:gpio 編號。

? label:gpio 名稱,可以為 NULL。

? 返回:

? 成功,返回 0。

? 失敗,返回錯誤碼。

4.2.2 gpio_free

? 函數(shù)原型:void gpio_free(unsigned gpio)

? 作用:釋放 gpio。

? 參數(shù):

? gpio:gpio 編號。

? 返回:

? 無返回值。

4.2.3 gpio_direction_input

? 函數(shù)原型:int gpio_direction_input(unsigned gpio)

? 作用:設置 gpio 為 input。

? 參數(shù):

? gpio:gpio 編號。

? 返回:

? 成功,返回 0。

? 失敗,返回錯誤碼。

4.2.5 __gpio_get_value

? 函數(shù)原型:int __gpio_get_value(unsigned gpio)

? 作用:獲取 gpio 電平值 (gpio 已為 input/output 狀態(tài))。

? 參數(shù):

? gpio:gpio 編號。

? 返回:

? 返回 gpio 對應的電平邏輯,1 表示高, 0 表示低。

4.2.6 __gpio_set_value

? 函數(shù)原型:void __gpio_set_value(unsigned gpio, int value)

? 作用:設置 gpio 電平值 (gpio 已為 input/output 狀態(tài))。

? 參數(shù):

? gpio:gpio 編號。

? value: 期望設置的 gpio 電平值,非 0 表示高, 0 表示低。

? 返回:

? 無返回值

4.2.7 of_get_named_gpio

? 函數(shù)原型:int of_get_named_gpio(struct device_node *np, const char *propname, int index)

? 作用:通過名稱從 dts 解析 gpio 屬性并返回 gpio 編號。

? 參數(shù):

? np: 指向使用 gpio 的設備結點。

? propname:dts 中屬性的名稱。

? index:dts 中屬性的索引值。

? 返回:

? 成功,返回 gpio 編號。

? 失敗,返回錯誤碼。

4.2.8 of_get_named_gpio_flags

? 函數(shù)原型:int of_get_named_gpio_flags(struct device_node *np, const char *list_name, int index,

enum of_gpio_flags *flags)

? 作用:通過名稱從 dts 解析 gpio 屬性并返回 gpio 編號。

? 參數(shù):

? np: 指向使用 gpio 的設備結點。

? propname:dts 中屬性的名稱。

? index:dts 中屬性的索引值

? flags: 在 sunxi 平臺上,必須定義為 struct gpio_config * 類型變量,因為 sunxi pinctrl的 pin 支持上下拉, 驅動能力等信息,而內核 enum of_gpio_flags * 類型變量只能包含輸入、輸出信息,后續(xù) sunxi 平臺 需要標準化該接口。

? 返回:

? 成功,返回 gpio 編號。

? 失敗,返回錯誤碼。

! 警告

該接口的 flags 參數(shù),在 sunxi linux-4.9 及以前的平臺上,必須定義為 struct gpio_config 類型變量。linux-5.4 已經標準化該接口,直接采用 enum of_gpio_flags 的定義。

5 使用示例

5.1 使用 pin 的驅動 dts 配置示例

對于使用 pin 的驅動來說,驅動主要設置 pin 的常用的幾種功能,列舉如下:

? 驅動使用者只配置通用 GPIO, 即用來做輸入、輸出和中斷的

? 驅動使用者設置 pin 的 pin mux,如 uart 設備的 pin,lcd 設備的 pin 等,用于特殊功能

? 驅動使用者既要配置 pin 的通用功能,也要配置 pin 的特性

下面對常見使用場景進行分別介紹。

5.1.1 配置通用 GPIO 功能/中斷功能

用法一:配置 GPIO,中斷,device tree 配置 demo 如下所示:

soc{

...

gpiokey {

device_type = "gpiokey";

compatible = "gpio-keys";

ok_key {

device_type = "ok_key";

label = "ok_key";

gpios = <&r_pio PL 0x4 0x0 0x1 0x0 0x1>; //如果是linux-5.4,則應該為gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>;

linux,input-type = "1>";

linux,code = <0x1c>;

wakeup-source = <0x1>;

};

};

...

};

說明

說明:gpio in/gpio out/ interrupt采用dts的配置方法,配置參數(shù)解釋如下:

對于linux-4.9:

gpios = <&r_pio PL 0x4 0x0 0x1 0x0 0x1>;

| | | | | | `---輸出電平,只有output才有效

| | | | | `-------驅動能力,值為0x0時采用默認值

| | | | `-----------上下拉,值為0x1時采用默認值

| | | `---------------復用類型

| | `-------------------當前bank中哪個引腳

| `-----------------------哪個bank

`---------------------------指向哪個pio,屬于cpus要用&r_pio

使用上述方式配置gpio時,需要驅動調用以下接口解析dts的配置參數(shù):

int of_get_named_gpio_flags(struct device_node *np, const char *list_name, int index,

enum of_gpio_flags *flags)

拿到gpio的配置信息后(保存在flags參數(shù)中,見4.2.8.小節(jié)),在根據需要調用相應的標準接口實現(xiàn)自己的功能

對于linux-5.4:

gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>;

| | |

| | `-------------------gpio active時狀態(tài),如果需要上下拉,還可以或上

GPIO_PULL_UP、GPIO_PULL_DOWN標志

| `-----------------------哪個bank

`---------------------------指向哪個pio,屬于cpus要用&r_pio

5.1.2 用法二

用法二:配置設備引腳,device tree 配置 demo 如下所示:

device tree對應配置 soc{ pio: pinctrl@0300b000 { ... uart0_ph_pins_a: uart0-ph-pins-a { allwinner,pins = "PH7", "PH8"; allwinner,function = "uart0"; allwinner,muxsel = <3>; allwinner,drive = <0x1>; allwinner,pull = <0x1>; }; /* 對于linux-5.4 請使用下面這種方式配置 */ mmc2_ds_pin: mmc2-ds-pin { pins = "PC1"; function = "mmc2"; drive-strength = <30>; bias-pull-up; }; ... }; ... uart0: uart@05000000 { compatible = "allwinner,sun8i-uart"; device_type = "uart0"; reg = <0x0 0x05000000 0x0 0x400>; interrupts = ; clocks = <&clk_uart0>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&uart0_pins_a>; pinctrl-1 = <&uart0_pins_b>; uart0_regulator = "vcc-io"; uart0_port = <0>; uart0_type = <2>; }; ... };

其中:

? pinctrl-0 對應 pinctrl-names 中的 default,即模塊正常工作模式下對應的 pin 配置

? pinctrl-1 對應 pinctrl-names 中的 sleep,即模塊休眠模式下對應的 pin 配置

5.2 接口使用示例

5.2.1 配置設備引腳

一般設備驅動只需要使用一個接口 devm_pinctrl_get_select_default 就可以申請到設備所有pin 資源。

static int sunxi_pin_req_demo(struct platform_device *pdev) { struct pinctrl *pinctrl; /* request device pinctrl, set as default state */ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR_OR_NULL(pinctrl)) return -EINVAL; return 0; }

5.2.2 獲取 GPIO 號

static int sunxi_pin_req_demo(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; unsigned int gpio; #get gpio config in device node. gpio = of_get_named_gpio(np, "vdevice_3", 0); if (!gpio_is_valid(gpio)) { if (gpio != -EPROBE_DEFER) dev_err(dev, "Error getting vdevice_3n"); return gpio; } }

5.2.3 GPIO 屬性配置

通過 pin_config_set/pin_config_get/pin_config_group_set/pin_config_group_get 接口單獨控制指定 pin 或 group 的相關屬性。

static int pctrltest_request_all_resource(void) { struct device *dev; struct device_node *node; struct pinctrl *pinctrl; struct sunxi_gpio_config *gpio_list = NULL; struct sunxi_gpio_config *gpio_cfg; unsigned gpio_count = 0; unsigned gpio_index; unsigned long config; int ret; dev = bus_find_device_by_name(&platform_bus_type, NULL, sunxi_ptest_data->dev_name); if (!dev) { pr_warn("find device [%s] failed...n", sunxi_ptest_data->dev_name); return -EINVAL; } node = of_find_node_by_type(NULL, dev_name(dev)); if (!node) { pr_warn("find node for device [%s] failed...n", dev_name(dev)); return -EINVAL; } dev->of_node = node; pr_warn("++++++++++++++++++++++++++++%s++++++++++++++++++++++++++++n", __func__); pr_warn("device[%s] all pin resource we want to requestn", dev_name(dev)); pr_warn("-----------------------------------------------n"); pr_warn("step1: request pin all resource.n"); pinctrl = devm_pinctrl_get_select_default(dev); if (IS_ERR_OR_NULL(pinctrl)) { pr_warn("request pinctrl handle for device [%s] failed...n", dev_name(dev)); return -EINVAL; } pr_warn("step2: get device[%s] pin count.n", dev_name(dev)); ret = dt_get_gpio_list(node, &gpio_list, &gpio_count); if (ret < 0 || gpio_count == 0) { ? ? ? ?pr_warn(" devices own 0 pin resource or look for main key failed!n"); ? ? ? ?return -EINVAL; ? ?} ? ?pr_warn("step3: get device[%s] pin configure and check.n", dev_name(dev)); ? ?for (gpio_index = 0; gpio_index < gpio_count; gpio_index++) { ? ? ? ?gpio_cfg = &gpio_list[gpio_index]; ? ? ? ?/*check function config */ ? ? ? ?config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0xFFFF); ? ? ? ?pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config); if (gpio_cfg->mulsel != SUNXI_PINCFG_UNPACK_VALUE(config)) { pr_warn("failed! mul value isn't equal as dt.n"); return -EINVAL; } /*check pull config */ if (gpio_cfg->pull != GPIO_PULL_DEFAULT) { config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, 0xFFFF); pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config); if (gpio_cfg->pull != SUNXI_PINCFG_UNPACK_VALUE(config)) { pr_warn("failed! pull value isn't equal as dt.n"); return -EINVAL; } } /*check dlevel config */ if (gpio_cfg->drive != GPIO_DRVLVL_DEFAULT) { config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, 0XFFFF); pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config); if (gpio_cfg->drive != SUNXI_PINCFG_UNPACK_VALUE(config)) { pr_warn("failed! dlevel value isn't equal as dt.n"); return -EINVAL; } } /*check data config */ if (gpio_cfg->data != GPIO_DATA_DEFAULT) { config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0XFFFF); pin_config_get(SUNXI_PINCTRL, gpio_cfg->name, &config); if (gpio_cfg->data != SUNXI_PINCFG_UNPACK_VALUE(config)) { pr_warn("failed! pin data value isn't equal as dt.n"); return -EINVAL; } } } pr_warn("-----------------------------------------------n"); pr_warn("test pinctrl request all resource success!n"); pr_warn("++++++++++++++++++++++++++++end++++++++++++++++++++++++++++nn"); return 0; } 注:需要注意,存在SUNXI_PINCTRL和SUNXI_R_PINCTRL兩個pinctrl設備,cpus域的pin需要使用 SUNXI_R_PINCTRL

! 警告

linux5.4 中 使 用 pinctrl_gpio_set_config 配 置 gpio 屬 性, 對 應 使 用pinconf_to_config_pack 生成 config 參數(shù):

? SUNXI_PINCFG_TYPE_FUNC 已不再生效,暫未支持 FUNC 配置(建議使用 pinctrl_select_state接口代替)

? SUNXI_PINCFG_TYPE_PUD 更新為內核標準定義(PIN_CONFIG_BIAS_PULL_UP/PIN_CONFIG_BIAS_PULL_DOWN

? SUNXI_PINCFG_TYPE_DRV 更新為內核標準定義(PIN_CONFIG_DRIVE_STRENGTH),相應的 val 對應關系為(4.9->5.4: 0->10, 1->20…

? SUNXI_PINCFG_TYPE_DAT 已不再生效,暫未支持 DAT 配置(建議使用 gpio_direction_output或者 __gpio_set_value 設置電平值)

5.3 設備驅動使用 GPIO 中斷功能

方式一:通過 gpio_to_irq 獲取虛擬中斷號,然后調用申請中斷函數(shù)即可目前 sunxi-pinctrl 使用 irq-domain 為 gpio 中斷實現(xiàn)虛擬 irq 的功能,使用 gpio 中斷功能時,設備驅動只需要通過 gpio_to_irq 獲取虛擬中斷號后,其他均可以按標準 irq 接口操作。

static int sunxi_gpio_eint_demo(struct platform_device *pdev) { struct device *dev = &pdev->dev; int virq; int ret; /* map the virq of gpio */ virq = gpio_to_irq(GPIOA(0)); if (IS_ERR_VALUE(virq)) { pr_warn("map gpio [%d] to virq failed, errno = %dn", GPIOA(0), virq); return -EINVAL; } pr_debug("gpio [%d] map to virq [%d] okn", GPIOA(0), virq); /* request virq, set virq type to high level trigger */ ret = devm_request_irq(dev, virq, sunxi_gpio_irq_test_handler, IRQF_TRIGGER_HIGH, "PA0_EINT", NULL); if (IS_ERR_VALUE(ret)) { pr_warn("request virq %d failed, errno = %dn", virq, ret); return -EINVAL; } return 0; }

方式二:通過 dts 配置 gpio 中斷,通過 dts 解析函數(shù)獲取虛擬中斷號,最后調用申請中斷函數(shù)即可,demo 如下所示:

dts配置如下: soc{ ... Vdevice: vdevice@0 { compatible = "allwinner,sun8i-vdevice"; device_type = "Vdevice"; interrupt-parent = <&pio>; /*依賴的中斷控制器(帶interrupt-controller屬性的結 點)*/ interrupts = < PD 3 IRQ_TYPE_LEVEL_HIGH>; | | `------------------中斷觸發(fā)條件、類型 | `-------------------------pin bank內偏移 `---------------------------哪個bank pinctrl-names = "default"; pinctrl-0 = <&vdevice_pins_a>; test-gpios = <&pio PC 3 1 2 2 1>; status = "okay"; }; ... };

在驅動中,通過 platform_get_irq() 標準接口獲取虛擬中斷號,如下所示:

static int sunxi_pctrltest_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct gpio_config config; int gpio, irq; int ret; if (np == NULL) { pr_err("Vdevice failed to get of_noden"); return -ENODEV; } .... irq = platform_get_irq(pdev, 0); if (irq < 0) { ? ? ? ?printk("Get irq error!n"); ? ? ? ?return -EBUSY; ? ?} ..... sunxi_ptest_data->irq = irq; ...... return ret; } //申請中斷: static int pctrltest_request_irq(void) { int ret; int virq = sunxi_ptest_data->irq; int trigger = IRQF_TRIGGER_HIGH; reinit_completion(&sunxi_ptest_data->done); pr_warn("step1: request irq(%s level) for irq:%d.n", trigger == IRQF_TRIGGER_HIGH ? "high" : "low", virq); ret = request_irq(virq, sunxi_pinctrl_irq_handler_demo1, trigger, "PIN_EINT", NULL); if (IS_ERR_VALUE(ret)) { pr_warn("request irq failed !n"); return -EINVAL; } pr_warn("step2: wait for irq.n"); ret = wait_for_completion_timeout(&sunxi_ptest_data->done, HZ); if (ret == 0) { pr_warn("wait for irq timeout!n"); free_irq(virq, NULL); return -EINVAL; } free_irq(virq, NULL); pr_warn("-----------------------------------------------n"); pr_warn("test pin eint success !n"); pr_warn("+++++++++++++++++++++++++++end++++++++++++++++++++++++++++nnn"); return 0; }

5.4 設備驅動設置中斷 debounce 功能

方式一:通過 dts 配置每個中斷 bank 的 debounce,以 pio 設備為例,如下所示:

&pio { /* takes the debounce time in usec as argument */ input-debounce = <0 0 0 0 0 0 0>; | | | | | | `----------PA bank | | | | | `------------PC bank | | | | `--------------PD bank | | | `----------------PF bank | | `------------------PG bank | `--------------------PH bank `----------------------PI bank };

注意:input-debounce 的屬性值中需把 pio 設備支持中斷的 bank 都配上,如果缺少,會以bank 的順序設置相應的屬性值到 debounce 寄存器,缺少的 bank 對應的 debounce 應該是默認值(啟動時沒修改的情況)。sunxi linux-4.9 平臺,中斷采樣頻率最大是 24M, 最小 32k,debounce 的屬性值只能為 0 或 1。對于 linux-5.4,debounce 取值范圍是 0~1000000(單位 usec)。

方式二:驅動模塊調用 gpio 相關接口設置中斷 debounce

static inline int gpio_set_debounce(unsigned gpio, unsigned debounce); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);

在驅動中,調用上面兩個接口即可設置 gpio 對應的中斷 debounce 寄存器,注意,debounce 是以 ms 為單位的 (linux-5.4 已經移除這個接口)。

6 FAQ

6.1 常用 debug 方法

6.1.1 利用 sunxi_dump 讀寫相應寄存器

需要開啟 SUNXI_DUMP 模塊:

make kernel_menuconfig ---> Device Drivers ---> dump reg driver for sunxi platform (選中)

使用方法:

cd /sys/class/sunxi_dump 1.查看一個寄存器 echo 0x0300b048 > dump ;cat dump 2.寫值到寄存器上 echo 0x0300b058 0xfff > write ;cat write 3.查看一片連續(xù)寄存器 echo 0x0300b000,0x0300bfff > dump;cat dump 4.寫一組寄存器的值 echo 0x0300b058 0xfff,0x0300b0a0 0xfff > write;cat write 通過上述方式,可以查看,修改相應gpio的寄存器,從而發(fā)現(xiàn)問題所在。

6.1.2 利用 sunxi_pinctrl 的 debug 節(jié)點

需要開啟 DEBUG_FS:

make kernel_menuconfig ---> Kernel hacking ---> Compile-time checks and compiler options ---> Debug Filesystem (選中)

掛載文件節(jié)點,并進入相應目錄:

mount -t debugfs none /sys/kernel/debug cd /sys/kernel/debug/sunxi_pinctrl

1.查看 pin 的配置:

echo PC2 > sunxi_pin cat sunxi_pin_configure

結果如下圖所示:

pYYBAGQFTdyAKqOOAAEjbf3Z7P8154.png

圖 6-1: 查看 pin 配置圖

2.修改 pin 屬性

每個 pin 都有四種屬性,如復用 (function),數(shù)據 (data),驅動能力 (dlevel),上下拉 (pull),

修改 pin 屬性的命令如下:

echo PC2 1 > pull;cat pull cat sunxi_pin_configure //查看修改情況

修改后結果如下圖所示:

pYYBAGQFTd2AVACBAAFXcULtto8056.png

圖 6-2: 修改結果圖

注意:在 sunxi 平臺,目前多個 pinctrl 的設備,分別是 pio 和 r_pio 和 axpxxx-gpio,當操作 PL 之后的 pin 時,請通過以下命令切換 pin 的設備,否則操作失敗,切換命令如下:

echo pio > /sys/kernel/debug/sunxi_pinctrl/dev_name //切換到pio設備 cat /sys/kernel/debug/sunxi_pinctrl/dev_name echo r_pio > /sys/kernel/debug/sunxi_pinctrl/dev_name //切換到r_pio設備 cat /sys/kernel/debug/sunxi_pinctrl/dev_name

修改結果如下圖所示:

poYBAGQFTd6ARZnqAACwhnIPDz0498.png

圖 6-3: pin 設備圖

6.1.3 利用 pinctrl core 的 debug 節(jié)點

mount -t debugfs none /sys/kernel/debug cd /sys/kernel/debug/sunxi_pinctrl

1.查看 pin 的管理設備:

cat pinctrl-devices

結果如下圖所示:

pYYBAGQFTd6AfS9DAADcI8zPtd4177.png

圖 6-4: pin 設備圖

2.查看 pin 的狀態(tài)和對應的使用設備

結果如下圖 log 所示:

console:/sys/kernel/debug/pinctrl # ls pinctrl-devices pinctrl-handles pinctrl-maps pio r_pio console:/sys/kernel/debug/pinctrl # cat pinctrl-handles Requested pin control handlers their pinmux maps: device: twi3 current state: sleep state: default type: MUX_GROUP controller pio group: PA10 (10) function: twi3 (15) type: CONFIGS_GROUP controller pio group PA10 (10)config 00001409 config 00000005 type: MUX_GROUP controller pio group: PA11 (11) function: twi3 (15) type: CONFIGS_GROUP controller pio group PA11 (11)config 00001409 config 00000005 state: sleep type: MUX_GROUP controller pio group: PA10 (10) function: io_disabled (5) type: CONFIGS_GROUP controller pio group PA10 (10)config 00001409 config 00000001 type: MUX_GROUP controller pio group: PA11 (11) function: io_disabled (5) type: CONFIGS_GROUP controller pio group PA11 (11)config 00001409 config 00000001 device: twi5 current state: default state: default type: MUX_GROUP controller r_pio group: PL0 (0) function: s_twi0 (3) type: CONFIGS_GROUP controller r_pio group PL0 (0)config 00001409 config 00000005 type: MUX_GROUP controller r_pio group: PL1 (1) function: s_twi0 (3) type: CONFIGS_GROUP controller r_pio group PL1 (1)config 00001409 config 00000005 state: sleep type: MUX_GROUP controller r_pio group: PL0 (0) function: io_disabled (4) type: CONFIGS_GROUP controller r_pio group PL0 (0)config 00001409 config 00000001 type: MUX_GROUP controller r_pio group: PL1 (1) function: io_disabled (4) type: CONFIGS_GROUP controller r_pio group PL1 (1)config 00001409 config 00000001 device: soc@03000000:pwm5@0300a000 current state: active state: active type: MUX_GROUP controller pio group: PA12 (12) function: pwm5 (16) type: CONFIGS_GROUP controller pio group PA12 (12)config 00000001 config 00000000 config 00000000 state: sleep type: MUX_GROUP controller pio group: PA12 (12) function: io_disabled (5) type: CONFIGS_GROUP controller pio group PA12 (12)config 00000001 config 00000000 config 00000000 device: uart0 current state: default state: default state: sleep device: uart1 current state: default state: default type: MUX_GROUP controller pio group: PG6 (95) function: uart1 (37) type: CONFIGS_GROUP controller pio group PG6 (95)config 00001409 config 00000005 type: MUX_GROUP controller pio group: PG7 (96) function: uart1 (37) type: CONFIGS_GROUP controller pio group PG7 (96)config 00001409 config 00000005 type: MUX_GROUP controller pio group: PG8 (97) function: uart1 (37) type: CONFIGS_GROUP controller pio group PG8 (97)config 00001409 config 00000005 type: MUX_GROUP controller pio group: PG9 (98) function: uart1 (37) type: CONFIGS_GROUP controller pio group PG9 (98)config 00001409 config 00000005 state: sleep type: MUX_GROUP controller pio group: PG6 (95) function: io_disabled (5) type: CONFIGS_GROUP controller pio group PG6 (95)config 00001409 config 00000001 type: MUX_GROUP controller pio group: PG7 (96) function: io_disabled (5) type: CONFIGS_GROUP controller pio group PG7 (96)config 00001409 config 00000001 type: MUX_GROUP controller pio group: PG8 (97) function: io_disabled (5) type: CONFIGS_GROUP controller pio group PG8 (97)config 00001409 config 00000001 type: MUX_GROUP controller pio group: PG9 (98) function: io_disabled (5) type: CONFIGS_GROUP controller pio group PG9 (98)config 00001409 ....

從上面的部分 log 可以看到那些設備管理的 pin 以及 pin 當前的狀態(tài)是否正確。以 twi3 設備為例,twi3 管理的 pin 有 PA10/PA11,分別有兩組狀態(tài) sleep 和 default,default 狀態(tài)表示使用狀態(tài),sleep 狀態(tài)表示 pin 處于 io disabled 狀態(tài),表示 pin 不可正常使用,twi3 設備使用的 pin 當前狀態(tài)處于 sleep 狀態(tài)的。

6.1.4 GPIO 中斷問題排查步驟

6.1.4.1 GPIO 中斷一直響應

排查中斷信號是否一直觸發(fā)中斷

利用 sunxi_dump 節(jié)點,確認中斷 pending 位是否沒有清 (參考 6.1.1 小節(jié))

是否在 gpio 中斷服務程序里對中斷檢測的 gpio 進行 pin mux 的切換,不允許這樣切換,否則會導致中斷異常

6.1.4.2 GPIO 檢測不到中斷

排查中斷信號是否正常,若不正常,則排查硬件,若正常,則跳到步驟 2

利用 sunxi_dump 節(jié)點,查看 gpio 中斷 pending 位是否置起,若已經置起,則跳到步驟5,否則跳到步驟 3

利用 sunxi_dump 節(jié)點,查看 gpio 的中斷觸發(fā)方式是否配置正確,若正確,則跳到步驟 4,否則跳到步驟 5

檢查中斷的采樣時鐘,默認應該是 32k,可以通過 sunxi_dump 節(jié)點,切換 gpio 中斷采樣時鐘到 24M 進行實驗

利用 sunxi_dump,確認中斷是否使能

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8504

    瀏覽量

    150843
  • Linux
    +關注

    關注

    87

    文章

    11230

    瀏覽量

    208937
  • GPIO
    +關注

    關注

    16

    文章

    1196

    瀏覽量

    51920
收藏 人收藏

    評論

    相關推薦

    EAC0945 linux開發(fā)指南

    EAC0945 linux開發(fā)指南
    發(fā)表于 09-28 12:40

    EAC0945 linux開發(fā)指南

    `EAC0945 linux開發(fā)指南`
    發(fā)表于 10-31 12:18

    I.MX6U嵌入式Linux驅動開發(fā)指南

    【正點原子Linux連載】第八章匯編LED燈試驗--摘自【正點原子】I.MX6U嵌入式Linux驅動開發(fā)指南V1.0`:---------:`第八章匯編LED燈試驗8.1 I.MX6U GPI
    發(fā)表于 01-26 08:26

    Rockchip Linux SDK uboot logo開發(fā)指南

    arm嵌入式vs-rk3399 板卡uboot logo 開發(fā)指南概述:本文檔主要介紹 rockchip linux sdk uboot logo 顯示的相關功能、配置以及開發(fā)過程中的注意事項。適用于 rockhip
    發(fā)表于 10-09 08:12

    CPLD FPGA高級應用開發(fā)指南

    CPLD FPGA高級應用開發(fā)指南
    發(fā)表于 04-15 10:56 ?58次下載
    CPLD FPGA高級應用<b class='flag-5'>開發(fā)指南</b>

    Tiny6410 Linux開發(fā)指南詳解

    Tiny6410 Linux 開發(fā)指南
    發(fā)表于 07-08 17:12 ?210次下載
    Tiny6410 <b class='flag-5'>Linux</b><b class='flag-5'>開發(fā)指南</b>詳解

    A64開發(fā)板LCD開發(fā)指南

    A64開發(fā)板LCD開發(fā)指南,驅動開發(fā)指南
    發(fā)表于 06-21 17:02 ?0次下載

    彩光燈開發(fā)指南

    彩光燈開發(fā)指南
    發(fā)表于 12-29 20:15 ?0次下載

    Linux的平臺下Mini210S裸機程序開發(fā)指南

    Linux的平臺下Mini210S裸機程序開發(fā)指南
    發(fā)表于 10-29 10:52 ?59次下載
    <b class='flag-5'>Linux</b>的平臺下Mini210S裸機程序<b class='flag-5'>開發(fā)指南</b>

    Rockchip Linux SDK的開發(fā)指南的詳細資料說明

    本文檔的主要內容詳細介紹的是Rockchip Linux SDK的開發(fā)指南的詳細資料說明。
    發(fā)表于 01-10 17:17 ?74次下載
    Rockchip <b class='flag-5'>Linux</b> SDK的<b class='flag-5'>開發(fā)指南</b>的詳細資料說明

    迅為RK3399開發(fā)板嵌入式linux開發(fā)指南

    迅為RK3399開發(fā)板嵌入式linux開發(fā)指南迅為RK3399開發(fā)板發(fā)布《北京迅為嵌入式linux開發(fā)指
    發(fā)表于 11-01 16:58 ?76次下載
    迅為RK3399<b class='flag-5'>開發(fā)</b>板嵌入式<b class='flag-5'>linux</b><b class='flag-5'>開發(fā)指南</b>

    Tina_Linux_系統(tǒng)軟件開發(fā)指南

    Tina_Linux_系統(tǒng)軟件開發(fā)指南
    的頭像 發(fā)表于 03-02 15:25 ?1776次閱讀
    Tina_<b class='flag-5'>Linux</b>_系統(tǒng)軟件<b class='flag-5'>開發(fā)指南</b>

    Tina Linux配置開發(fā)指南

    Tina Linux配置開發(fā)指南
    的頭像 發(fā)表于 03-02 15:28 ?1.6w次閱讀
    Tina <b class='flag-5'>Linux</b>配置<b class='flag-5'>開發(fā)指南</b>

    Linux NOR開發(fā)指南

    Linux NOR開發(fā)指南
    的頭像 發(fā)表于 03-06 09:55 ?925次閱讀
    <b class='flag-5'>Linux</b> NOR<b class='flag-5'>開發(fā)指南</b>

    【北京迅為】itop-龍芯2k1000開發(fā)指南Linux基礎入門vim 編輯器

    【北京迅為】itop-龍芯2k1000開發(fā)指南Linux基礎入門vim 編輯器
    的頭像 發(fā)表于 10-25 14:56 ?254次閱讀
    【北京迅為】itop-龍芯2k1000<b class='flag-5'>開發(fā)指南</b><b class='flag-5'>Linux</b>基礎入門vim 編輯器