前言
注: 所有文章基于linux-3.13以上,本系列主要介绍 GPIO的一些基本知识,驱动操作GPIO的接口,应用层通过sysfs操作GPIO的接口,GPIO一些debug信息查看,以及对高通相关GPIO的寄存器操作。分享给刚刚接触外设bsp的小伙伴们。当然后面有时间还会分享GPIO子系统框架和pinctrl子系统框架,先知道黑盒怎么使用,然后咱再打开仔细瞅瞅。
本篇为驱动申请GPIO和操作GPIO接口篇,分别介绍驱动通过GPIO子系统和PINCTRL 子系统提供的接口对GPIO的操作
GPIO 子系统操作GPIO
GPIO子系统接口简介
相关实现在driver/gpio/gpiolib.c 下
1、gpio_request 申请GPIO
?
int?gpio_request(unsigned?gpio,?const?char?*label)
?
参数解析:
gpio: gpio编号
label: 名称
返回值: 成功返回0,失败返回负值
2、gpio_request_one 申请GPIO,同时制定配置方式 输出或输入模式
?
int?gpio_request_one(unsigned?gpio,?unsigned?long?flags,?const?char?*label)
?
3、gpio_free 释放GPIO
?
void?gpio_free(unsigned?gpio)
?
参数解析:
gpio: gpio编号
4、gpio_direction_input 设置GPIO为输入模式
?
int?gpio_direction_input(unsigned?gpio)
?
参数解析:
gpio: gpio编号
返回值: 成功返回0,失败返回负值
5、gpio_direction_output 设置GPIO为输出模式
?
int?gpio_direction_output(unsigned?gpio,?int?value)
?
参数解析:
gpio: gpio编号
value: 设置为输出模式时的初始值
返回值: 成功返回0,失败返回负值
6、gpio_set_value 设置(写)GPIO的值
?
void?__gpio_set_value(unsigned?gpio,?int?value) #define?gpio_set_value??__gpio_set_value
?
gpio: gpio编号
value: 设置的值
返回值: 成功返回0,失败返回负值
7、gpio_get_value 获取(读)GPIO的值
?
int?__gpio_get_value(unsigned?gpio) #define?gpio_get_value??__gpio_get_value
?
gpio: gpio编号
返回值: 获取的值
8、gpio_to_irq 内核通过调用该函数将gpio端口转换为中断
?
int?gpio_to_irq(unsigned?gpio);?
?
gpio: gpio编号
返回值:中断编号可以传给request_irq()和free_irq()
举个例子:单个GPIO
申请gpio4,输出模式,输出高(从设备树配置)
设备树设置
?
gpio_test{ ?status="ok"; ?gpio_req=<&tlmn?4?0>;
?
代码实现
?
struct?device?dev; gpio4?=?of_get_named_gpio(dev.of_node,"gpio_req",?0); err?=?gpio_request(gpio4,?"qti-can-reset"); ?if?(err?0)?{ ?????????return?err; ?}? gpio_direction_output(gpio4,?0);???????????????? gpio_set_value(gpio4,1);????????????????
?
GPIO数组申请一个gpio数组 [36,42,132],主要是设备树 设备树
?
gpios?=?<&tlmm?36?0>, ????????????????<&tlmm?42?0>, ????????????????<&tlmm 132 0>; ????????qcom,gpio-reset?=?<1>; ????????qcom,gpio-standby?=?<2>; ????????qcom,gpio-req-tbl-num?=?<0?1?2>;?? ????????qcom,gpio-req-tbl-flags?=?<1?0?0>;? ????????qcom,gpio-req-tbl-label?=?"CAMIF_MCLK2",?? ????????????????????????????????????????????????????????????????"CAM_RESET2", ???????????????????????????????????????????????????????????????"CAM_STANDBY2";
?
解析:
PINCTRL 子系统操作GPIO
pinctrl 子系统相关接口
1、devm_pinctrl_get 解析对应的设备树,获取pinctrl资源
?
struct?pinctrl?*devm_pinctrl_get(struct?device?*dev)
?
dev: 驱动设备结构体
返回值:pinctrl节点
2、pinctrl_lookup_state 获取各种state的gpio配置
?
struct?pinctrl_state?*pinctrl_lookup_state(struct?pinctrl?*p,?const?char?*name)?
?
p: pinctrl节点
name:gpio配置的名字
3、pinctrl_select_state 将上面获取的指定state状态设置到硬件中*/
?
int?pinctrl_select_state(struct?pinctrl?*p,?struct?pinctrl_state?*state)
?
举个例子
高通的配置为例子
在pinctrl设备树添加一个节点
?
&tlmn{ ? ?pin_teset_default:pin_teset_default{ ?????????????????mux?{ ??????????????????????????pins?=?"gpio0",?"gpio1";? ??????????????????????????function?=?"qup00"; ??????????????????}; ??????????????????config?{ ??????????????????????????pins?=?"gpio0",?"gpio1";? ??????????????????????????drive-strength?=?<2>; ??????????????????????????bias-disable; ??????????????????}; ?} }
?
在xxx.dtsi中添加一个设备 使用
?
pinctrl_test{ ??status="ok"; ??pinctrl-name="default"; ??pinctrl-0=<&pin_teset_default>; }
?
代码实现
?
dev->pins->p?=?devm_pinctrl_get(dev); ?dev->pins->default_state?=?pinctrl_lookup_state(dev->pins->p,?PINCTRL_STATE_DEFAULT);? ??pinctrl_select_state(dev->pins->p,?dev->pins->default_state);
?
probe自动配置pinctrl
如上个例子中,我们是不需要自己进行pinctrl适配的,device和驱动在匹配之后会进行适配。调用我们驱动的probe时,pinctrl相关已经初始化好了。获取相关状态和设置相关状态
?
__device_attach ????bus_for_each_drv(dev->bus,?NULL,?&data,?__device_attach_driver); ????????__device_attach_driver? ????????????driver_match_device(drv,?dev);? ????????????driver_probe_device(struct?device_driver?*drv,?struct?device?*dev) ????????????????really_probe ????????????????????pinctrl_bind_pins? ????????????????????????drv->probe(dev) int?pinctrl_bind_pins(struct?device?*dev) { ??? ???dev->pins->p?=?devm_pinctrl_get(dev); ??? ???dev->pins->default_state?=?pinctrl_lookup_state(dev->pins->p,?PINCTRL_STATE_DEFAULT);? ???dev->pins->init_state?=?pinctrl_lookup_state(dev->pins->p,?PINCTRL_STATE_INIT); ??? ???if?(IS_ERR(dev->pins->init_state))?{ ??????? ???????ret?=?pinctrl_select_state(dev->pins->p,?dev->pins->default_state);? ???}?else?{ ???????ret?=?pinctrl_select_state(dev->pins->p,?dev->pins->init_state); ???} #ifdef?CONFIG_PM? ???dev->pins->sleep_state?=?pinctrl_lookup_state(dev->pins->p,?PINCTRL_STATE_SLEEP); ???dev->pins->idle_state?=?pinctrl_lookup_state(dev->pins->p,?PINCTRL_STATE_IDLE); #endif ???return?0; }
?
?
审核编辑:汤梓红
评论