Linux BSP 開發的基礎就是和GPIO打交道, 下面總結下這幾天對某家開發板的GPIO控制的知識。node
公司的開發板用的是 DTB 模式 ,首先,進入 dts,dtsi文件查看關於GPIO 的模塊。linux
soc { . . . gpio0: gpio@****addr { compatible = "**********"; reg = <0 0x****addr 0 0x50>; interrupts = <SPI 4 IRQ_TYPE_LEVEL_HIGH>; #gpio-cells = <2>; gpio-controller; gpio-ranges = <&pfc 0 0 16>; #interrupt-cells = <2>; interrupt-controller; clocks = <&cpg CPG_MOD 912>; power-domains = <*****>; }; . . . };
能夠看到 GPIO 節點 掛在 SOC node 下 ,手上這塊開發板 把GPIO分紅了8個 bank : gpio0 - gpio7ios
reg =<0 地址 0 長度> bash
#gpio-cells =<2> 表示 要用2個cell描述一個 GPIO引腳 dom
如 I2C中定義 : pwd-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>;this
表示 bank 6 的gpio 用 2個cell 描述 :7,GPIO_ACTIVE_HIGH (7表示bank 6 下的第七個引腳通常是 GP 6_07表示 ;GPIO_ACTIVE_HIGH則爲高電平有效) spa
gpio-controller; interrupt-controller; 表示 bank 0 下的引腳 既能夠做爲中斷引腳 ,也能夠做爲 通用的GPIO引腳 code
gpio-ranges = <&pfc 0 0 16>; 表示 bank 0下有16個 GPIO引腳 orm
GPIO 使用 pinctrl 方式來驅動 ,pin control subsystem 會 :對象
1. 枚舉全部可用的pin 腳 ,因而每一個引腳就有的惟一的 ID (num) ,這個ID 很關鍵,對於之後的操做。
enum { PINMUX_RESERVED = 0, PINMUX_DATA_BEGIN, GP_ALL(DATA), /* add GP_0_1_DATA ,GP_0_1_DATA..... */ PINMUX_DATA_END, #define F_(x, y) ..... }
2.管理 這些Pin腳的, 因爲pin 能夠複用 好比 SPI 和GPIO 複用一個pin腳 如: GP2_08 / MISO,因而引伸出 pin group 和 pin functon 兩個概念:
i2c2_pins: i2c2 { groups = "i2c2_a"; function = "i2c2"; };
在dts 中如上所示 ,其中 i2c2_a 在 pinctl 源碼中 以下所示,i2c的兩根引腳使用 GP5_0 ,GP5_4.
static const unsigned int i2c2_a_pins[] = { /* SDA, SCL */ GP_PIN(5, 0),GP_PIN(5, 4), };
function 以下 :
struct sh_pfc_function { const char *name; const char * const *groups; unsigned int nr_groups; }; #define SH_PFC_FUNCTION(n = i2c2) \ { \ .name = #n, \ .groups = n##_groups, \ .nr_groups = ARRAY_SIZE(n##_groups), \ }
好了 ,基本概念就先寫這麼多 。
在 寫內核驅動的時候 若是但願配置某個GPIO引腳 , 能夠在dts中 添加: pwd-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
在 driver 代碼中 , 須要包含 #include <linux/gpio.h>使用 :
gpio_id = of_get_named_gpio(your_driver->dev->of_node,"pwd-gpios", 0);
獲取 GP0_07的 ID號 ,而後申請 一個GPIO 操做對象。
if (gpio_is_valid(gpio_id)) //判斷一個IO是否合法
devm_gpio_request_one(&platform_device->dev, gpio_id,GPIOF_OUT_INIT_LOW, name);
設置GPIO的方向,若是是輸出同時設置電平:
/* set as input or output, returning 0 or negative errno */
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
獲取輸入引腳的電平:
/* GPIO INPUT: return zero or nonzero */
int gpio_get_value(unsigned gpio);
設置輸出:
void gpio_set_value(unsigned gpio, int value);
釋放申請的GPIO對象
void gpio_free(unsigned gpio);
將GPIO映射爲IRQ中斷:
/* map GPIO numbers to IRQ numbers */
int gpio_to_irq(unsigned gpio);
/* map IRQ numbers to GPIO numbers (avoid using this) */
int irq_to_gpio(unsigned irq);
設置GPIO IRQ中斷類型:
set_irq_type(gpio_to_irq( gpio), IRQ_TYPE_EDGE_FALLING);
須要確認 內核 menuconfig 中 Device Drivers -》 GPIO Support 設 y .
在 /sys/class/gpio 目錄下以下所示 :
root@salvator-x:/sys/class/gpio# ls export gpiochip361 gpiochip419 gpiochip453 gpiochip496 gpiochip357 gpiochip393 gpiochip437 gpiochip468 unexport
gpiochip 後面的數字 是每一個bank 的基地址 也就是 GP0 對應 gpiochip468
那麼 GP0_07 的 ID 就是 468 + 7 ;(可能不一樣的內核版本,或者 開發板不同 )經過 :
root@salvator-x:/sys/class/gpio# echo 475 > export
會對應生成 gpio475 目錄
root@salvator-x:/sys/class/gpio/gpio475# ls active_low device direction edge power subsystem uevent value
經過
root@salvator-x:/sys/class/gpio/gpio475# echo 1 >value root@salvator-x:/sys/class/gpio/gpio475# echo 0 >value root@salvator-x:/sys/class/gpio/gpio475# echo "in" > direction root@salvator-x:/sys/class/gpio/gpio475# echo "out" > direction
來控制輸出輸入 ,電平高低 。
最後,關於 Pinctrl 的內容還有太多要寫,就先寫到這把。。。。。
來不及寫 參考文檔了,具體是 結合 wowotech 和 公司的設備,要下班了。。。
ADD :..........................................................................
獲取GPIO不一樣組 基地址的 bash 命令 :
for i in gpiochip* ; do echo `cat $i/label`: `cat $i/base` ; done