瑞芯微Rockchip开发者社区
直播中

douyin8

12年用户 1118经验值
私信 关注
[问答]

如何定义GPIO有哪些功能可以复用呢

如何定义GPIO有哪些功能可以复用?在运行时又如何切换功能呢?

回帖(1)

许青云

2022-2-15 14:26:06
以I2C4为例作简单的介绍。
查规格表可知,I2C4_SDA与I2C4_SCL的功能定义如下:
#func0func1I2C4_SDA/GPIO1_B3gpio1b3i2c4_sdaI2C4_SCL/GPIO1_B4gpio1b4i2c4_scl
在kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi里有:
i2c4:i2c@ff3d0000{;reg=<0x00xff3d00000x00x1000>;clocks=pmucruSCLK_I2C4_PMU>,pmucruPCLK_I2C4_PMU>;,"pclk";interrupts=;,"gpio";pinctrl-0=i2c4_xfer>;pinctrl-1=i2c4_gpio>;//此处源码未添加#address-cells=<1>;#size-cells=<0>;;};
此处,跟复用控制相关的是pinctrl-开头的属性:pinctrl-names定义了状态名称列表:default(i2c功能)和gpio两种状态。
pinctrl-0定义了状态0(即default)时需要设置的pinctrl:&i2c4_xfer
pinctrl-1定义了状态1(即gpio)时需要设置的pinctrl:&i2c4_gpio
这些pinctrl在kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi中这样定义:
pinctrl:pinctrl{;rockchip,grf=grf>;rockchip,pmu=pmugrf>;#address-cells=<0x2>;#size-cells=<0x2>;ranges;i2c4{i2c4_xfer:i2c4-xfer{rockchip,pins=<112RK_FUNC_1&pcfg_pull_none>,<111RK_FUNC_1&pcfg_pull_none>;};i2c4_gpio:i2c4-gpio{rockchip,pins=<112RK_FUNC_GPIO&pcfg_pull_none>,<111RK_FUNC_GPIO&pcfg_pull_none>;};};
RK_FUNC_1,RK_FUNC_GPIO的定义在kernel/include/dt-bindings/pinctrl/rk.h中:
#defineRK_FUNC_GPIO0#defineRK_FUNC_11#defineRK_FUNC_22#defineRK_FUNC_33#defineRK_FUNC_44#defineRK_FUNC_55#defineRK_FUNC_66#defineRK_FUNC_77
另外,像”111”,”112”这样的值是有编码规则的,编码方式与上一小节”输入输出”描述的一样,”111”代表GPIO1_B3,”112”代表GPIO1_B4。
在复用时,如果选择了“default”(即i2c功能),系统会应用i2c4_xfer这个pinctrl,最终将GPIO1_B3和GPIO1_B4两个针脚切换成对应的i2c功能;而如果选择了“gpio”,系统会应用i2c4_gpio这个pinctrl,将GPIO1_B3和GPIO1_B4两个针脚还原为GPIO功能。
我们看看i2c的驱动程序kernel/drivers/i2c/busses/i2c-rockchip.c是如何切换复用功能的:
staticintrockchip_i2c_probe(structplatform_device*pdev){structrockchip_i2c*i2c=NULL;structresource*res;structdevice_node*np=pdev->dev.of_node;intret;//...i2c->sda_gpio=of_get_gpio(np,0);if(!gpio_is_valid(i2c->sda_gpio)){dev_err(&pdev->dev,"sdagpioisinvalidn");return-EINVAL;}ret=devm_gpio_request(&pdev->dev,i2c->sda_gpio,dev_name(&i2c->adap.dev));if(ret){dev_err(&pdev->dev,"failedtorequestsdagpion");returnret;}i2c->scl_gpio=of_get_gpio(np,1);if(!gpio_is_valid(i2c->scl_gpio)){dev_err(&pdev->dev,"sclgpioisinvalidn");return-EINVAL;}ret=devm_gpio_request(&pdev->dev,i2c->scl_gpio,dev_name(&i2c->adap.dev));if(ret){dev_err(&pdev->dev,"failedtorequestsclgpion");returnret;}i2c->gpio_state=pinctrl_lookup_state(i2c->dev->pins->p,"gpio");if(IS_ERR(i2c->gpio_state)){dev_err(&pdev->dev,"nogpiopinctrlstaten");returnPTR_ERR(i2c->gpio_state);}pinctrl_select_state(i2c->dev->pins->p,i2c->gpio_state);gpio_direction_input(i2c->sda_gpio);gpio_direction_input(i2c->scl_gpio);pinctrl_select_state(i2c->dev->pins->p,i2c->dev->pins->default_state);//...}
首先是调用of_get_gpio取出设备树中i2c4结点的gpios属于所定义的两个gpio:
gpios=gpio1GPIO_B3GPIO_ACTIVE_LOW>,gpio1GPIO_B4GPIO_ACTIVE_LOW>;
然后是调用devm_gpio_request来申请gpio,接着是调用pinctrl_lookup_state来查找“gpio”状态,而默认状态“default”已经由框架保存到i2c->dev-pins->default_state中了。
最后调用pinctrl_select_state来选择是“default”还是“gpio”功能。
下面是常用的复用API定义:
#includestructdevice{//...#ifdefCONFIG_PINCTRLstructdev_pin_info*pins;#endif//...};structdev_pin_info{structpinctrl*p;structpinctrl_state*default_state;#ifdefCONFIG_PMstructpinctrl_state*sleep_state;structpinctrl_state*idle_state;#endif};structpinctrl_state*pinctrl_lookup_state(structpinctrl*p,constchar*name);intpinctrl_select_state(structpinctrl*p,structpinctrl_state*s);
举报

更多回帖

发帖
×
20
完善资料,
赚取积分