做底層驅動免不了gpio打交道,所以對其操作和調試進行了一下簡單的梳理
一、gpio的調試方法
在Linux下,通過sysfs,獲取gpio狀態,也可以操作gpio。
1、獲取gpio狀態
cd /sys/kernel/debug/
cat gpio
2、操作gpio(以gpio99為例)
cd /sys/class/gpio/
echo 99 > export
cd gpio99
echo in/out > direction //設置gpio輸入或輸出
cat direction //獲取gpio輸入輸出狀態
echo 'value' > value //設置gpio寄存器值
cat value //獲取gpio寄存器的值
二、在kernel代碼中操作gpio
在代碼中有兩種方式操作gpio,一種是一次申請單個gpio,成功后操縱該gpio,另一種是使用pinctrl,通過設備樹設置,一次操作多個gpio。
1、方法1
設備樹設備節點中添加gpio //可選
device_node {
...
gpio_name = <&tlmm 99 0>; //gpio_99
...
}
驅動代碼:
- int gpio_99 = of_get_named_gpio_flags(dev->of_node, "gpio_name", 0, NULL); //從設備數節點, 可選
- gpio_request(gpio_99, "gpio_name"); //通過gpio號申請gpio
- gpio_direction_output(gpio_99, 1); //設置gpio_99輸出,初始值為1
- gpio_set_value(gpio_99, 0); //設置gpio_99值為0
- gpio_free(gpio_99); //gpio_99不再使用后應當釋放
注:
gpio的申請和設置都可能會出現失敗的情況,應該做好異常處理
2、方法二
設備樹代碼:
平台pinctrl節點下添加如下子節點:
相關文檔和設備樹配置詳解見kernel/Document/pinctrl.txt和Documentation/devicetree/bindings/pinctrl/下多個文件
gpio_group {
gpio_active: gpio_active {
mux {
pins = "gpio99", "gpio98"; //復用引腳99和98
functions = "gpio"; //引腳功能配置為普通gpio
};
config {
pins = "gpio99", "gpio98";
drive-strength = <8>; //最大電流限制為8mA
bias-pull-up; //配置上拉
output-high; //輸出高電平
};
};
gpio_sleep: gpio_sleep {
mux {
pins = "gpio99", "gpio98"; //復用引腳99和98
functions = "gpio"; //引腳功能配置為普通gpio
};
config {
pins = "gpio99", "gpio98";
drive-strength = <2>; //最大電流限制為2mA
bias-no-pull; //不上拉也不下拉
output-low; //輸出低電平
};
};
設備節點中引用pinctrl:
device_node {
...
pinctrl-names = "gpio_active", "gpio_sleep"; //分別對用pinctrl-0和pinctrl-1
pinctrl-0 = <&gpio_active>; //引用
pinctrl-1 = <&gpio_sleep>; //引用
...
};
內核驅動代碼:
- struct pinctrl *pinctrl = devm_pinctrl_get(device); //獲取device對應節點下的pinctrl
- struct pinctrl_state = pinctrl_lookup_state(pinctrl, "gpio_active"); //通過pinctrl名獲取pinctrl對應狀態
- pinctrl_select_state(pinctrl, pinctrl_state); //設置pinctrl的狀態為'gpio_active
- devm_pinctrl_put(pinctrl); //使用完了釋放資源
也可以同時使用方法一和方法二,方法一操作簡單,但是只能拉高或拉低,而方法二可全面配置GPIO。在一個設備驅動中同時使用方法一和方法二可保證資源不被其他模塊操作。