日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下的gpio,gpiod

發布時間:2023/12/20 linux 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下的gpio,gpiod 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

GPIO 應該是每個嵌入式設備都避免不了的。最近在做項目的時候,也遇到這方面的問題,所以簡單總結一下

現在內核里面多了gpiod的來控制gpio口,相對于原來的形式,使用gpiod的好處是我們申請后不進行free也沒有什么問題。但是你要是使用原來的方式后,一定要記得釋放。不釋放的話可能會有問題。

#舊的GPIO使用實例

DTS文件

det-gpios = <&gpio3 RK_PA6 IRQ_TYPE_EDGE_BOTH>;

驅動文件調用

gc5025->det_pin?=?of_get_named_gpio_flags(node,?"det-gpios",?0,?&det_flags);camera_det_irq?=?gpio_to_irq(gc5025->det_pin);gc5025->det_value?=?gpio_get_value(gc5025->det_pin);/*判斷注冊終端*/if(camera_det_irq){if?(gpio_request(gc5025->det_pin,?"camera-irq-gpio"))?{printk("gpio?%d?request?failed!\n",?gc5025->det_pin);gpio_free(gc5025->det_pin);return?IRQ_NONE;}ret?=?request_irq(camera_det_irq,?camera_det_irq_handler,?IRQ_TYPE_EDGE_BOTH,?"det-gpio",?NULL);if?(ret?!=?0)?{free_irq(camera_det_irq,?NULL);dev_err(dev,?"Failed?to?request?IRQ:?%d\n",?ret);return?ret;}}

# 新的GPIOD文檔

Linux 內核文檔

https://www.kernel.org/doc/Documentation/gpio/consumer.txt

#頭文件

我們需要包含頭文件

#include <linux/gpio/consumer.h>

看頭文件里面包含的函數列表

desc_to_gpio devm_get_gpiod_from_chi devm_gpiod_get devm_gpiod_get_array devm_gpiod_get_array_op devm_gpiod_get_index devm_gpiod_get_index_op devm_gpiod_get_optional devm_gpiod_put devm_gpiod_put_array fwnode_get_named_gpiod gpio_to_desc gpiod_cansleep gpiod_count gpiod_direction_input gpiod_direction_output gpiod_direction_output_ gpiod_export gpiod_export_link gpiod_get gpiod_get_array gpiod_get_array_optiona gpiod_get_direction gpiod_get_index gpiod_get_index_optiona gpiod_get_optional gpiod_get_raw_value gpiod_get_raw_value_can gpiod_get_value gpiod_get_value_canslee gpiod_is_active_low gpiod_put gpiod_put_array gpiod_set_array_value gpiod_set_array_value_c gpiod_set_debounce gpiod_set_raw_array_val gpiod_set_raw_array_val gpiod_set_raw_value gpiod_set_raw_value_can gpiod_set_value gpiod_set_value_canslee gpiod_to_irq gpiod_unexport

#獲取gpio描述符和釋放

使用一下兩個函數獲取GPIO設備,多個設備時需要附帶index參數。函數返回一個GPIO描述符,或一個錯誤編碼,可以使用IS_ERR()進行檢查:

struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,enum gpiod_flags flags)struct gpio_desc *gpiod_get_index(struct device *dev,const char *con_id, unsigned int idx,enum gpiod_flags flags)

或者也可以使用如下兩個函數獲取可用設備:

struct gpio_desc *gpiod_get_optional(struct device *dev,const char *con_id,enum gpiod_flags flags)struct gpio_desc *gpiod_get_index_optional(struct device *dev,const char *con_id,unsigned int index,enum gpiod_flags flags)

使用如下函數同時獲取多個設備:

struct gpio_descs *gpiod_get_array(struct device *dev,const char *con_id,enum gpiod_flags flags)

該函數返回一個GPIO描述結構體:

struct gpio_descs {unsigned int ndescs;struct gpio_desc *desc[]; }

一個GPIO描述符可以使用如下函數釋放:

void gpiod_put(struct gpio_desc *desc) void gpiod_put_array(struct gpio_descs *descs)

需要注意GPIO描述符被釋放后不可再使用,而且不允許使用第一個函數來釋放通過序列獲取得到GPIO描述符。

#舉個例子

#dts文件

gc5025: gc5025@37 {status = "okay";compatible = "galaxycore,gc5025";reg = <0x37>;clock-frequency = <400000>;pinctrl-names = "default";pinctrl-0 = <&cif_clkout_m0>;clocks = <&cru SCLK_CIF_OUT>;clock-names = "xvclk";avdd-supply = <&vcc2v8_dvp>;dovdd-supply = <&vcc1v8_dvp>;dvdd-supply = <&vdd1v2_dvp>;reset-gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;pwdn-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;det-gpios = <&gpio3 RK_PA6 IRQ_TYPE_EDGE_BOTH>;rockchip,camera-module-index = <0>;rockchip,camera-module-facing = "front";rockchip,camera-module-name = "CMK-CW4191-FG1";rockchip,camera-module-lens-name = "CK5502";port {ucam_out: endpoint {remote-endpoint = <&mipi_in_ucam>;data-lanes = <1 2>;};};};

驅動文件調用:

????gc5025->reset_gpio?=?devm_gpiod_get(dev,?"reset",?GPIOD_OUT_LOW);if?(IS_ERR(gc5025->reset_gpio))dev_warn(dev,?"Failed?to?get?reset-gpios\n");gc5025->pwdn_gpio?=?devm_gpiod_get(dev,?"pwdn",?GPIOD_OUT_LOW);if?(IS_ERR(gc5025->pwdn_gpio))dev_warn(dev,?"Failed?to?get?pwdn-gpios\n");/*新的GPIO子系統方式,這種方式不需要手動釋放資源*/gc5025->det_gpio?=?devm_gpiod_get(dev,?"det",?GPIOD_OUT_LOW);if?(IS_ERR(gc5025->det_gpio))

#GPIO使用

#設置GPIO口方向

int gpiod_direction_input(struct gpio_desc *desc) int gpiod_direction_output(struct gpio_desc *desc, int value)

#檢查GPIO口是方向

int gpiod_get_direction(const struct gpio_desc *desc)

函數返回GPIOF_DIR_IN或者GPIOF_DIR_OUT

#讀取GPIO口電平

訪問分為兩種,一種是通過儲存器讀寫實現的,這種操作屬于原子操作,不需要等待,所以可以在中斷處理程序中使用:

int gpiod_get_value(const struct gpio_desc *desc); void gpiod_set_value(struct gpio_desc *desc, int value);

還有一種訪問必須通過消息總線比如I2C或者SPI,這種訪問需要在總線訪問隊列中等待,所以可能進入睡眠,此類訪問不能出現在IRQ handler。可以使用如下函數分辨這些設備:

int gpiod_cansleep(const struct gpio_desc *desc)

使用如下函數讀寫:

int gpiod_get_value_cansleep(const struct gpio_desc *desc) void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)

#active-low和raw-value

active-low & raw value有些設備采用低電平有效的方式輸出邏輯信號。此時低電平輸出1,高電平輸出0。此時可以通過訪問raw_value的方式來訪問實際電路上的值,與邏輯處理無關:假設我們在DTS里面這樣設置

reset-gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;

然后我們這樣調用

gpiod_set_value_cansleep(gc5025->reset_gpio, 1);

因為DTS里面的active 狀態是 GPIO_ACTIVE_LOW,所以這個代碼輸出的是 低電平

gpiod_set_value_cansleep(gc5025->reset_gpio, 0);

輸出的是高電平

這幾個函數如下:

int gpiod_get_raw_value(const struct gpio_desc *desc) void gpiod_set_raw_value(struct gpio_desc *desc, int value) int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) int gpiod_direction_output_raw(struct gpio_desc *desc, int value)

raw-value 的意思就是不在乎DTS里面的ACTIVE,我set 高電平,就是高電平。邏輯關系匯總如下:

Function (example) active-low property physical line gpiod_set_raw_value(desc, 0); don’t care low gpiod_set_raw_value(desc, 1); don’t care high gpiod_set_value(desc, 0); default (active-high) low gpiod_set_value(desc, 1); default (active-high) high gpiod_set_value(desc, 0); active-low high gpiod_set_value(desc, 1); active-low low

可以使用如下函數判斷一個設備是否是低電平有效的設備。

int gpiod_is_active_low(const struct gpio_desc *desc)

#設置多個輸出

這個沒使用過 使用如下函數設置一組設備的輸出值

void gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, int *value_array) void gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, int *value_array) void gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, int *value_array) void gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, int *value_array)

#兼容舊版本

舊的GPIO系統使用基于標號的結構而不是基于描述符。可以使用如下兩個函數進行相互轉換:

int desc_to_gpio(const struct gpio_desc *desc) struct gpio_desc *gpio_to_desc(unsigned gpio)

注意不能使用一套API的方法釋放另一套API獲取的設備

#和中斷IRQ相關

使用如下函數獲取一個GPIO設備對應的IRQ中斷號

int gpiod_to_irq(const struct gpio_desc *desc)

返回值時一個IRQ number,或者一個負數的錯誤代碼。得到的中斷號可以傳遞給函數request_irq(),free_irq().

#舉例子

/*新的GPIO子系統方式,這種方式不需要手動釋放資源*/gc5025->det_gpio = devm_gpiod_get(dev, "det", GPIOD_OUT_LOW);if (IS_ERR(gc5025->det_gpio))dev_warn(dev, "Failed to get det-gpios\n");camera_det_irq = gpiod_to_irq(gc5025->det_gpio);/*新gpio子系統轉成舊gpio子系統*/gc5025->det_pin = desc_to_gpio(gc5025->det_gpio);/*讀取上電gpio電平*/gc5025->det_value = gpio_get_value(gc5025->det_pin);/*判斷注冊終端*/if(camera_det_irq){ret = request_irq(camera_det_irq, camera_det_irq_handler, IRQ_TYPE_EDGE_BOTH, "det-gpio", NULL);if (ret != 0) {free_irq(camera_det_irq, NULL);dev_err(dev, "Failed to request IRQ: %d\n", ret);return ret;}}

#調試

移植驅動階段或者調試階段的工程中,難免想知道當前gpio的電平狀態。當然很easy。萬用表戳上去不就行了。是啊!硬件工程師的思維。作為軟件工程師自然是要軟件的方法。下面介紹兩個api接口。自己摸索使用吧。點到為止。

static inline int gpio_export(unsigned gpio, bool direction_may_change); static inline int gpio_export_link(struct device *dev, const char *name, unsigned gpio);

在你的driver中調用以上api后,編譯下載。去/sys/class/gpio目錄看看有什么發現。

? 回復「?籃球的大肚子」進入技術群聊

回復「1024」獲取1000G學習資料

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的Linux下的gpio,gpiod的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。