当前位置: 首页 > 工具软件 > Firefly > 使用案例 >

gpio rk3399 控制_Firefly-RK3399--GPIO简介

富凯旋
2023-12-01

复用

如何定义GPIO有哪些功能可以复用,在运行时又如何切换功能呢?以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{compatible="rockchip,rk3399-i2c";reg=<0x00xff3d00000x00x1000>;clocks=pmucruSCLK_I2C4_PMU>,pmucruPCLK_I2C4_PMU>;clock-names="i2c","pclk";interrupts=;pinctrl-names="default","gpio";pinctrl-0=i2c4_xfer>;pinctrl-1=i2c4_gpio>;//此处源码未添加#address-cells=<1>;#size-cells=<0>;status="disabled";};

此处,跟复用控制相关的是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{compatible="rockchip,rk3399-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,"sdagpioisinvalid\n");return-EINVAL;}ret=devm_gpio_request(&pdev->dev,i2c->sda_gpio,dev_name(&i2c->adap.dev));if(ret){dev_err(&pdev->dev,"failedtorequestsdagpio\n");returnret;}i2c->scl_gpio=of_get_gpio(np,1);if(!gpio_is_valid(i2c->scl_gpio)){dev_err(&pdev->dev,"sclgpioisinvalid\n");return-EINVAL;}ret=devm_gpio_request(&pdev->dev,i2c->scl_gpio,dev_name(&i2c->adap.dev));if(ret){dev_err(&pdev->dev,"failedtorequestsclgpio\n");returnret;}i2c->gpio_state=pinctrl_lookup_state(i2c->dev->pins->p,"gpio");if(IS_ERR(i2c->gpio_state)){dev_err(&pdev->dev,"nogpiopinctrlstate\n");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);

 类似资料: