pinctrl 子系统的 API 有很多,对于驱动工程师来说,pinctrl 操作一个 GPIO 只需要三步:
1、devm_pinctrl_get
2、pinctrl_lookup_state
3、pinctrl_select_state
在 Linux 中,加 devm_ 开头的函数,代表这个函数支持资源管理。一般情况下,我们写一个驱动程序,在程序开头都会申请资源,比如内存、中断号等,万一后面哪一步申请出错,我们要回滚到第一步,去释放已经申请的资源,这样很麻烦。后来 Linux 开发出了很多 devm_ 开头的函数,代表这个函数有支持资源管理的版本,不管哪一步出错,只要错误退出,就会自动释放所申请的资源。
1)devm_pinctrl_get:用于获取设备树中自己用 pinctrl 建立的节点的句柄;
2) pinctrl_lookup_state:用于选择其中一个 pinctrl 的状态,同一个 pinctrl 可以有很多状态。比如 GPIO50 , 一开始初始化的时候是 I2C ,设备待机时候,我希望切换到普通 GPIO 模式,并且配置为下拉输入,省电 。这时候如果 pinctrl 节点有描述,我们就可以在代码中切换 pin 的功能,从 I2C 功能切换成普通 GPIO 功能;
3) pinctrl_select_stat:用于真正设置,在上一步获取到某个状态以后,这一步真正设置为这个状态。
对于 pinctrl 子系统的设备树配置,是遵守 service 和 client 结构 。
client 端各个平台基本都是一样的,server 端每个平台都不一样,使用的字符串的配置也不一样。
设备树配置:
//client端,设置不同状态
&test {
pinctrl-names = "default","test_low","test_high";
pinctrl-0 = < &test_default >;
pinctrl-1 = < &test_low >;
pinctrl-2 = < &test_high >;
gpio = < &gpio5 1 GPIO_ACTIVE_LOW >;
status = "okay";
};
//server 即 pin controller 端,设置 GPIO 几种功能状态
&gpio5 {
test_default:test_default{};
test_low:test_low{
fsl,pins = <
MX6UL_PAD_GPIO5_IO01__GPIO5_IO01 0x17059
>
};
test_high:test_low{
fsl,pins = <
MX6UL_PAD_GPIO5_IO01__GPIO5_IO01 0x1b0b1
>
};
};
pinctrl.c
#include < linux/init.h >
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/platform_device.h >
#include < linux/delay.h >
#include < linux/pinctrl/pinctrl.h >
#include < linux/pinctrl/consumer.h >
static int __init mypinctrl_init(void)
{
int ret = 0;
struct pinctrl *pctrl;
struct platform_device *pdev;
struct pinctrl_state *test_high;
struct pinctrl_state *test_low;
pctrl = devm_pinctrl_get(&pdev- >dev);
if(IS_ERR(pctrl)){
ret = PTR_ERR(pctrl);
printk("devm_pinctrl_get errorn");
return ret;
}
test_high = pinctrl_lookup_state(pctrl,"test_high");
if(IS_ERR(pctrl)){
ret = PTR_ERR(test_high);
printk("pinctrl_lookup_state test_high errorn");
return ret;
}
test_low = pinctrl_lookup_state(pctrl,"test_low");
if(IS_ERR(pctrl)){
ret = PTR_ERR(test_low);
printk("pinctrl_lookup_state test_low errorn");
return ret;
}
pinctrl_select_state(pctrl,test_low);
udelay(200);
pinctrl_select_state(pctrl,test_high);
return 0;
}
static void __exit mypinctrl_exit(void)
{
printk("%sn",__func__);
}
module_init(mypinctrl_init);
module_exit(mypinctrl_exit);
MUDULE_LICENSE("GPL");
Makefile 与上面相同,只是更改一下编译输出的名字。
这个驱动加载上去,可以切换GPIO口的功能状态,我这里只是控制GPIO输出高低,具体看你设备树怎么配,比如你可以配置某个GPIO一开始是I2C功能,待机时候是普通GPIO功能,达到省电的目的。
全部0条评论
快来发表一下你的评论吧 !