1. 應用空間控制gpio
1.1簡介
在/sys/class/gpio/下有個export文件,向export文件寫入要操作的GPIO號,使得該GPIO的操作接口從內核空間暴露到用戶空間,GPIO的操作接口包括direction和value等,direction控制GPIO輸入或者輸出模式,而value可控制GPIO的狀態或者讀取狀態。
/sys/class/gpio/目錄下各個文件說明:
/sys/class/gpio/export文件用於通知系統需要導出控制的GPIO引腳編號;
/sys/class/gpio/unexport 用於通知系統取消導出;
/sys/class/gpio/gpioX/direction文件,可以寫入in(設置輸入方向)或out(設置輸出方向);
/sys/class/gpio/gpioX/value文件是可以讀寫GPIO狀態;
/sys/class/gpio/gpiochipX目錄保存系統中GPIO寄存器的信息,包括每個寄存器控制引腳的起始編號,寄存器名稱,引腳總數;其中X表示具體的引腳編號。
1.2操作gpio
比如我要操作GPIO8_A6作爲高電平輸出有效, 那麼有以下三個操作:
1. 2.1 換算對應的gpio number
可以通過/sys/kernel/debug/gpio查詢信息:
root@rk3288:/sys/kernel/debug # cat gpio
GPIOs 184-215, platform/ff770000.pinctrl, gpio6:
GPIOs 216-247, platform/ff770000.pinctrl, gpio7:
gpio-218 (enable ) out hi
gpio-221 (gslX680 wake pin ) out hi
gpio-222 (gslX680 irq pin ) out lo
gpio-223 (headset_gpio ) in hi
GPIOs 248-279, platform/ff770000.pinctrl, gpio8:
GPIOs 280-311, platform/ff770000.pinctrl, gpio15:
可以看到gpio8是以nubmer爲248開始, 那麼GPIO8_A6就是 248 + 6 = 254,接下來就可以導出gpio了。
root@rk3288:/sys/class/gpio
root@rk3288:/sys/class/gpio
1.2.2 設置成輸出
root@rk3288:/sys/class/gpio/gpio254
root@rk3288:/sys/class/gpio/gpio254
1.2.3 輸出高電平
root@rk3288:/sys/class/gpio/gpio254
root@rk3288:/sys/class/gpio/gpio254
1.3 總結
這種方式一般不採用,爲了gpio使用的安全性,一般是不將gpio的使用權暴露給應用層的,即sys/class/下沒有gpio節點。
2. 內核空間控制gpio
在內核空間控制gpio有兩種方法,第一種是通過調用gpiolib的接口來控制gpio;第二種是通過ioremap來控制gpio。
2.1 gpiolib控制gpio
2.1.1 gpiolib簡介
Linux Kernel 中對 GPIO 資源進行了抽象,抽象出一個叫做 Gpiolib 的東西。
中間層是 Gpiolib,用於管理系統中的 GPIO。Gpiolib 彙總了 GPIO 的通用操作,根據 GPIO 的特性,Gpiolib 對上(其他 Drivers)提供的一套統一通用的操作 GPIO 的軟件接口,屏蔽了不同芯片的具體實現。對下,Gpiolib 提供了針對不同芯片操作的一套 framework,針對不同芯片,只需要實現 Specific Chip Driver ,然後使用 Gpiolib 提供的註冊函數,將其掛接到 Gpiolib 上,這樣就完成了這一套東西。
2.1.2 Gpiolib 爲其他驅動提供的 APIs
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
int gpio_set_value(unsigned gpio);
2.1.3 操作gpio
功能和1.2一樣。
ret = gpio_request(GPIO8_A6 , "gpio8_a6");
printk("request for gpio8_a6 failed:%d\n", ret);
gpio_direction_output(GPIO8_A6 ,1);
2.2 ioremap控制gpio
這種方法會降低程序的可讀性,不建議使用。
linux內核空間訪問的地址爲虛擬地址(3~4GB),故在內核空間操作某個寄存器時,需先通過ioremap函數將物理地址映射成虛擬地址。
用ioremap() 獲取寄存器的地址:
unsigned int __iomem *base_addr1;
#define GPIO8_REGBASE (0x20A0000)
#define GPIO8_A6 (*(volatile unsigned int *)(base_addr1 + 6))
base_addr1 = ioremap(GPIO8_REGBASE, 0x14)
通過 readl() 或者 writel() 函數直接操作映射後的地址:
使用完後,取消映射:
iounmap(base_addr1);
3. 查看GPIO全部信息
cat /sys/kernel/debug/pinctrl/pinctrl/pinmux-pins
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (gpio0-0): wireless-wlan (GPIO UNCLAIMED) function wireless-wlan group wifi-wake-host
pin 1 (gpio0-1): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 2 (gpio0-2): (MUX UNCLAIMED) gpio0:2
pin 3 (gpio0-3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 4 (gpio0-4): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 5 (gpio0-5): (MUX UNCLAIMED) gpio0:5
pin 6 (gpio0-6): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 7 (gpio0-7): (MUX UNCLAIMED) gpio0:7
pin 8 (gpio0-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 9 (gpio0-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 10 (gpio0-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 11 (gpio0-11): ff050000.i2c (GPIO UNCLAIMED) function i2c1 group i2c1-xfer
pin 12 (gpio0-12): ff050000.i2c (GPIO UNCLAIMED) function i2c1 group i2c1-xfer
pin 13 (gpio0-13): (MUX UNCLAIMED) (GPIO UNCLAIMED)
根據對比實驗,“MUX UNCLAIMED” 的意思好像是該複用引腳未被配置,僅個人小實驗,不具備絕對準確性。