linux核心gpiolib__linux

來源:互聯網
上載者:User
標識連接埠 -------------
gpio使用0~MAX_INT之間的整數標識,不能使用負數。 使用以下函數檢查一個連接埠號碼的合法性: int gpio_is_valid(int number);
使用gpio ------------- 使用io的第一步是分配連接埠,使用 gpio_request()。 接下來要做的是標記它的方向。 /*設為輸入或者輸出,成功返回零或者失敗返回負的錯誤值*/  int gpio_direction_input(unsigned gpio);  int gpio_direction_output(unsigned gpio, int value); 通常應該檢查它們的傳回值。通常應該假定這兩個介面會線上程上下文中調用。但是 對於自旋鎖安全的gpio也可以線上程出現之前的早期初始化之間使用。
對於輸出的gpio,提供的值作為輸出的初始值。
使用自旋鎖安全的gpio ---------------------------------- 大部分gpio控制器可以使用記憶體讀寫指令來訪問,不需要睡眠,可以在中斷上下文訪問。
對於gpio_cansleep返回假的gpio可以使用下面的介面訪問: /*讀取輸入,返回零或非零*/ int gpio_get_value(unsigned gpio); /*輸出*/ void gpio_set_value(unsigned gpio, int value); 返回的值是布爾值,零代表低,非零代表搞電平。當讀取輸出引腳的值,傳回值應該是引腳上的實際狀態, 這個值不一定等於配置的輸出值,因為從設定訊號到訊號穩定需要一定時間。
不是所有的平台可以讀取輸出的引腳值,這些平台不能總是返回零。用這兩這兩個函數訪問 不能非在睡眠的上下文中安全訪問的gpio將是一個錯誤。
可被休眠上下文中訪問的GPIO ---------------------------------------------- 一些gpio控制器必須使用基於資訊的匯流排,比如i2c和spi.讀寫gpio值的命令需要在隊列中等待。 操作這些gpio可能會睡眠,不能在中斷上下文中調用。
支援這種gpio的平台為了通過在這個函數中返回非零來區分其它 類型的gpio(需要一個已經被gpio_request申請的gpio號): int gpio_cansleep(unsigned gpio);
為了訪問這些連接埠,定義了另一組函數介面: /*輸入連接埠:返回零或非零,可能睡眠*/ int gpio_get_value_cansleep(unsigned gpio); /*輸出連接埠:可能睡眠*/ void gpio_set_value_cansleep(unsigned gpio, int value); 只能在允許睡眠的上下文中訪問這些連接埠,比如線程化的中斷中, 必須使用這些介面而不是沒有cansleep首碼的自旋鎖安全介面。
除了這些介面可能睡眠這個事實之外,它們操作那些不能在中斷處理函數中訪問的連接埠,這些調用的表現和 自旋鎖安全的調用表現一致。
另外:調用安裝和配置這樣的gpio必須是在可睡眠的上下文中,因為他們可能需要訪問gpio控制器。         gpio_direction_input()         gpio_direction_output()         gpio_request()
##      gpio_request_one() ##      gpio_request_array() ##      gpio_free_array()
        gpio_free()          gpio_set_debounce()

申請和釋放gpio ------------------------ 為了擷取系統配置錯誤,定義了兩個調用: /*申請gpio,返回0或負的錯誤值 * 非空的lables指標有助於診斷*/ int gpio_request(unsigned gpio, const char *label); /*釋放之前申請的gpio*/ void gpio_free(unsigned gpio); 應該假設這兩個函數實在進程上下文中調用的,但對於自旋鎖安全的gpio也可從 在進程建立之前的早期啟動過程中調用。
考慮到大多數情況下gpio會在申請過後立即需要被配置,下面三個介面負責這些工作:
/*申請一個單獨的gpio,使用“flag”作為初始的配置參數*/int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);/*在一個調用中申請多個gpio*/int gpio_request_array(struct gpio *array, size_t num);/*釋放多個連接埠*/void gpio_free_array(struct gpio *array, size_t num);


“flag”用來配置下面的特性:            * GPIOF_DIR_IN              - 配置方向為輸入          * GPIOF_DIR_OUT         -配置方向為輸出            * GPIOF_INIT_LOW        - 做輸出引腳,輸出低電平          * GPIOF_INIT_HIGH       - 做輸出引腳,輸出高電平
為了同時處理多個gpio,定義了一個專門結構體:          struct gpio {                  unsigned        gpio;                  unsigned long   flags;                  const char      *label;          };

典型的使用如下:

static struct gpio leds_gpios[] = {                { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */                { 33, GPIOF_OUT_INIT_LOW,  "Green LED" }, /* default to OFF */                { 34, GPIOF_OUT_INIT_LOW,  "Red LED"   }, /* default to OFF */                { 35, GPIOF_OUT_INIT_LOW,  "Blue LED"  }, /* default to OFF */                { ... },        };        err = gpio_request_one(31, GPIOF_IN, "Reset Button");        if (err)                ...        err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));        if (err)                ...        gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios)); 

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_direction_input()安裝的gpio編號或者不是從 gpio_to_irq()得到的中斷號是不會被gpio檢查的錯誤。
gpio_to_irq()返回的中斷編號可以傳給request_irq()和free_irq()。 irq_to_gpio()返回的gpio編號通常用來調用gpio_get_value(),比如在沿觸發的中斷中擷取引腳的狀態。 有些平台不支援這種映射,應該避免調用映射函數。
類比漏極開路 ------------------ gpio可能支援也可能不支援漏極開路輸出。如果硬體不支援,可以類比漏極開路輸出的輸入或者輸出: LOW:    gpio_direction_output(gpio, 0)  忽略上拉電阻。 HIGH:    gpio_direction_input(gpio) 關閉輸出,上拉電阻控制訊號。 如果驅動輸出高電平但是gpio_get_value(gpio)報告的電平是低電平(經過一定延遲之後),可以斷定 其它部分正在訊號線上輸出低電平。
GPIO 的架構(可選) =============== GPIO的架構在gpiolib中實現。 如果使能了 debugfs,系統下會出現 /sys/kernel/debug/gpio這個檔案。這個檔案內 將會列出所有註冊在架構內的控制器和當前使用的gpio的狀態。
控制器驅動:gpio_chip ------------------------------- 在gpio架構中使用"struct gpio_chip"表示每個控制器的所有資訊: --設定gpio方向的方法 --訪問gpio狀態的方法 --表示是否會睡眠的標誌 --可選的debugfs方法 --診斷用的標籤lable(char指標) 當然還有每個執行個體的專屬資料(可能來自dev.platform_data);第一個gpio的編號和管理的gpio數量。
gpiolib支援多個gpio控制器的執行個體,使用gpiochip_add()來註冊,使用gpiochip_remove()登出。 gpio_chip的debugfs方法將會忽略未被申請的gpio。使用gpiochip_is_requested()將會返回NULL(未被申請)或者 lable(已被申請)
平台支援 ------------ 為了支援gpio架構,必須選擇Kconfig中的選項:ARCH_REQUIRE_GPIOLIB 或者 ARCH_WANT_OPTIONAL_GPIOLIB。並且 在 <asm/gpio.h>包含<asm-generic/gpio.h>,還要定義三個函數: gpio_get_value(), gpio_set_value(), and gpio_cansleep(). 同時也可以提供ARCH_NR_GPIOS的定義,以反映平台支援的gpio數量。
ARCH_REQUIRE_GPIOLIB表示gpiolib代碼總是會編譯進核心中。 ARCH_WANT_OPTIONAL_GPIOLIB表示gpiolib預設是關閉的,但是使用者可以使能它並把它編譯進核心。 如果這兩個選項一個都未被選中,gpiolib則不能被使用者使能。
通常那三個函數介面可以直接使用架構內的代碼(通過gpio_chip來調用):              #define gpio_get_value        __gpio_get_value              #define gpio_set_value        __gpio_set_value              #define gpio_cansleep         __gpio_cansleep

使用者空間的sysfs介面(可選) ==================
在sysfs下的路徑 --------------------- 在/sys/class/gpio下有三種類型的入口:             --使用者空間控制GPIO的介面(第一類)             --對應具體GPIO             --GPIO控制器("gpio_chip"的執行個體)(第三類) 以上介面不包括標準“device”檔案和它們的連結。
控制介面(第一類)是唯寫的:             /sys/class/gpio/                         "export" 使用者空間通過寫入gpio的編號來向核心申請將某個gpio的控制權匯出到使用者空間                                     比如“echo 19 > export ”將會為19號gpio建立一個節點“gpio19”,前提是沒有內和代碼申請了這個連接埠。                         “unexport” 和匯出的效果相反。                                     比如“echo 19 > unexport”將會移除“gpio19”這個節點。 GPIO管腳的路徑類似於/sys/class/gpio/gpio42/ (for GPIO #42)的形式,並且有以下可讀寫的屬性:             /sys/class/gpio/gpioN/   (第二類)                         “direction” 讀取結果是“in”或者“out”。也可以往其中寫入。寫入“out”預設將引腳值初始化為低。                                     寫入“low”或“high”可以初始化作為輸出時的初始值。                                     如果核心不支援或者核心代碼不願意,將不會存在這個屬性。                         “value” 讀取結果是0(低電平)或1(高電平)。如果GPIO被配置為輸出,這個值是可寫的,                                     任何非零的值都將輸出高電平。                                     如果某個引腳能並且已經被配置為產生中斷,可以在它的節點上調用poll(2)並且poll(2)將在中斷觸發後返回。                                     如果使用poll(2),設定事件類型為POLLPRI和POLLERR。如果使用sellect(2),將檔案描述符加入exceptfds。                                     在poll(2)返回後,可以使用lseek(2)移動到檔案開頭讀取新的值或者關閉它再重新開啟讀取新值。                         “edge”   讀取改節點將會得到以下值: "none", "rising", "falling",或者  "both"。寫如這些字串到這個節點中將會選擇                                     喚醒在“value”上的poll(2)的訊號沿。                                     這個檔案節點只有在引腳能被配置為輸入中斷引腳的時候才存在。                         "active_low" 讀取值是0(假)或者1(真)。寫入任何非零的值都將反轉“value”中讀取和寫入的值。                                     已經在使用和之後使用poll(2)的“edge”節點的“rasing”和“falling”值將會受"active_low" 的影響。                                     (自己的理解:這個值實際是將高變為0,低變為1。也就是實現了邏輯反轉。)
GPIO控制器的路徑類似於/sys/class/gpio/gpiochip42/(這個控制器的最小連接埠是42)並且有以下的讀寫屬性:             /sys/class/gpio/gpiochipN/                         “base” 和N相同,也就是控制器管理的最小的連接埠編號。                         “lable”  診斷使用的標誌(並不總是唯一的)                         “ngpio” 控制器管理的連接埠數量(連接埠範圍是:N ~ N+ngpio-1)

從核心空間中匯出 ------------------------ 核心可以對已經被 gpio_request()申請的gpio的匯出進行明確的管理。           /* 匯出GPIO到使用者空間的sysfs,當允許使用者空間修改gpio的方向,第二個參數是真 */            int gpio_export(unsigned gpio, bool direction_may_change);

          /* 撤銷GPIO的匯出 */            void gpio_unexport();

          /* 建立到匯出GPIO的sysfs link ,第一個參數是在哪個dev下建立,第二個參數名字,第三個是gpio編號 */            int gpio_export_link(struct device *dev, const char *name, unsigned gpio)

          /* 改變sysfs中GPIO節點的極性,也就是將高低電平的邏輯反轉。可以在export之前和之後進行。之前設定的enabled poll(2)也會相應改變  */            int gpio_sysfs_set_active_low(unsigned gpio, int value);

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 以上內容是核心文檔的內容,下面分析gpio_chip的內容,這是一個控制器。   48/**   49 * struct gpio_chip - 一個 GPIO 控制器的抽象   50 * @label: 診斷用的標籤(名字)   51 * @dev: 可選的裝置結構體   52 * @owner: 擁有者模組指標   53 * @request: 可選的啟用回呼函數,就像電源管理的介面一樣。可以睡眠   55 * @free: 可選的釋放回呼函數,可以睡眠。   57 * @direction_input: 配置某個位移對應的連接埠為輸入引腳,可能返回錯誤。   58 * @get: 返回相應位移引腳的值; 如果是輸出引腳則返回輸出引腳的狀態,或者返回零。   60 * @direction_output: 配置輸出引腳的輸出值,或者返回錯誤   61 * @set: 設定指定引腳的輸出值。   62 * @to_irq: 可選的回呼函數,支援非靜態gpio_to_irq()映射, 不可以睡眠 ;   64 * @dbg_show: 可選的 debugfs介面; 如果不設定,核心會使用預設函數賦給這個指標。   67 * @base: gpiogpio_chip所管理的第一個gpio的編號;如果註冊期間是負值,將會動態申請一個值。   69 * @ngpio: GPIO控制器管理的IO數目,最後一個IO的號碼是 (base + ngpio - 1).   71 * @can_sleep: 如果get()/set() 方法會睡眠這個標誌必須被設定   73 * @names:如果設定了這個成員,它必須是大小為ngpio的字元指標數組,每個成員可以指向相應引腳的特殊的名字,也可以為空白。              name影響的是exportGPIO到sysfs的名字,如果不設定的話名字就是“gpioN”(N是IO對應的編號)。               當然這個成員可以不初始化。
gpio_chip使用offset(0~(ngpio - 1))來分辨不同的引腳。
struct gpio_chip {        const char              *label;        struct device           *dev;        struct module           *owner;        int                     (*request)(struct gpio_chip *chip,                                                unsigned offset);        void                    (*free)(struct gpio_chip *chip,                                                unsigned offset);        int                     (*direction_input)(struct gpio_chip *chip,                                                unsigned offset);        int                     (*get)(struct gpio_chip *chip,                                                unsigned offset);        int                     (*direction_output)(struct gpio_chip *chip,                                                unsigned offset, int value);        int                     (*set_debounce)(struct gpio_chip *chip,                                                unsigned offset, unsigned debounce);        void                    (*set)(struct gpio_chip *chip,                                                unsigned offset, int value);        int                     (*to_irq)(struct gpio_chip *chip,                                                unsigned offset);        void                    (*dbg_show)(struct seq_file *s,                                                struct gpio_chip *chip);        int                     base;        u16                     ngpio;        const char              *const *names;        unsigned                can_sleep:1;        unsigned                exported:1;#if defined(CONFIG_OF_GPIO)        /*         * If CONFIG_OF is enabled, then all GPIO controllers described in the         * device tree automatically may have an OF translation         */        struct device_node *of_node;        int of_gpio_n_cells;        int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,                        const void *gpio_spec, u32 *flags);#endif};         
gpio_chip的介面:
extern const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset); 如果offet對應的gpio已經被申請了則返回NULL,否則返回lable指標或者“。。”


extern int __must_check gpiochip_reserve(int start, int ngpio);
將start開始的ngpio個編號保留
這個函數是在全域範圍內預留一段編號,將來供某個gpio_chip使用。

附gpiolib架構圖(基於s5pv210):



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.