pinctrl和gpio子系统

 

pinctrl和gpio子系统

1、pincrtl子系统

传统配置pin的方式是直接操作寄存器,这种方式比较繁琐和容易出问题,pinctrl子系统就是为了解决这个问题而引入的。pinctrl子系统的主要工作内容如下:

●获取设备树中的pin信息

●根据获取到的pin信息来设置pin的复用功能

●根据获取到的pin信息来设置pin的电气特性,比如上下拉,速度,驱动能力等

对于使用者来说,在设备树提供相应的信息就可以了,pinctrl子系统会来完成剩下的工作。

 

使用pinctrl的另外一个好处是,驱动代码与单板无关。

pinctrl涉及到两个概念,pin controller和client device

前者提供服务:可以用它来复用引脚、配置引脚

后者使用服务:声明自己要使用哪些引脚的哪些功能,怎么配置他们。

 

pin controller节点的格式没有统一标准!!!!每家芯片都不一样,由芯片BSP厂商定义。pinctrl子系统,芯片相关的操作也是需要BSP厂商编写代码并注册给内核。所以pin controller节点属性的格式,跟BSP厂商的风格关联比较大。

如imx6ull的引脚配置由iomuxc模块负责,pin controller就在该节点下实现

&iomuxc {
……
pinctrl_test: testgrp { 
fsl,pins = < 
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 config /*config是具体设置值*/ 
 >;
};

上面的fsl,pins属性的值如下:

#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0

展开相应的宏发现是5个值,实际上是对应了

<mux_reg conf_reg input_reg mux_mode input_val>

IMX芯片IO配置寄存器的地址和设置的值。

从这个宏的名字也能想到就是配置PAD_UART1_RTS_B这个引脚的功能为GPIO1_IO19。后面跟着的config是配置上下拉,驱动能力,速度等电气特性。

上面这个pinctrl的节点信息,IMX有个Pins_Tool_for_i.MX_Processors软件可以通过UI界面生成。

 

下面就是不同芯片的pin controller的定义,可以发现属性名称不太一样,但是使用的概念是一样的。都是用controller节点配置引脚,client device设备使用引脚。

pinctrl子系统在用户driver的作用流程

         ●设置了pin controller的引脚配置

         ●在client device引用了引脚配置

         ●在设备状态切换的时候,pinctrl会被自动调用如:

2、gpio子系统

pinctrl子系统重点是配置PAD的复用和电气特性,如果pinctrl子系统将一个PAD复用为GPIO的话,接下来就要用到gpio子系统。gpio子系统的主要目的是方便驱动开发这使用gpio,开发出来的驱动也可以做到和单板无关。

在BSP工程师实现了GPIO子系统后,我们可以:

  • 在设备树里指定GPIO引脚
  • 在驱动代码中:使用GPIO子系统的标准函数控制IO

a、设备树中指定GPIO的格式

BSP定义了GPIO Controller如:imx芯片的定义

在设备树的模块节点加入IO的引用:

格式为gpios属性,或者name-gpios属性

如上面的reset引脚,用的是gpio5的引脚2

b、gpio接口函数

获取GPIO

gpiod_get

gpiod_get_index

gpiod_get_array

devm_gpiod_get

devm_gpiod_get_index

devm_gpiod_get_array

设置方向

gpiod_direction_input

gpiod_direction_output

读值写值

gpiod_get_value

gpiod_set_value

释放GPIO

gpio_free

gpiod_put

gpiod_put_array

devm_gpiod_put

devm_gpiod_put_array

3、pinctrl和gpio子系统使用例子(IMX6ULL SOC芯片为例子)

●设备树相关节点编写

3.1添加pinctrl节点

用Pins_Tool_for_i.MX_Processors_v6_x64.exe工具生成pinctrl配置

或者自己手动根据厂家的规则编写

pinctrl_io:iogrp{
		fsl,pins=<
			MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0 /* IO */
		>;
};

将该节点添加到iomuxc节点

3.2添加IO设备节点

gpiotest{
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = “test-io”;
		pinctrl-names = “default”;
		pinctrl-0 = <&pinctrl_io>;				/* 引用IO配置*/	
		io-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;	/* 引用GPIO*/	
		status = “okay”;
}

●IO驱动编写

    a.定义、注册一个platform_driver

    b.在probe函数里面:

       根据platform_device的设备树信息确定GPIO:gpiod_get

    c在file_operations的函数中使用GPIO子系统的函数操作GPIO:

        gpiod_direction_output、gpiod_set_value

a.定义、注册platform_driver的参考代码

static const struct of_device_id test_io[] = {
{ .compatible = "test-io" },
{ },
};

/* 1. 定义platform_driver */
static struct platform_driver chip_demo_gpio_driver = {
   				 .probe      = chip_demo_gpio_probe,
   				 .remove     = chip_demo_gpio_remove,
   			     .driver    = {
       		     .name   = "test_io",
      		     .of_match_table = test_io,
   				 },
};

/* 2. 在入口函数注册platform_driver */
static int __init io_init(void)
{
int err;
err = platform_driver_register(&chip_demo_gpio_driver);
}

 

b. 在probe函数中获得GPIO参考代码
/*   从platform_device获得GPIO
*    把file_operations结构体告诉内核:注册驱动程序
*/

Static struct gpio_desc *io_gpio;

static int chip_demo_gpio_probe(struct platform_device *pdev)
{
//int err;
/* 4.1 设备树中定义有: io-gpios=<...>; */
io_gpio = gpiod_get(&pdev->dev, "io", 0);   
//这里注意是io而不是io-gpios,跟踪代码发现gpiod_get后面会自动补全-gpios后缀
 }

 

c.	使用GPIO子系统的函数操作GPIO

在open函数中调用GPIO函数设置引脚方向:
static int io_drv_open (struct inode *node, struct file *file)
{
		gpiod_direction_output(io_gpio, 0);
		return 0;
}
			
在write函数中调用GPIO函数设置引脚值:
/* write(fd, &val, 1); */
static ssize_t io_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
char status;
err = copy_from_user(&status, buf, 1);
/* 设置IO的状态 */
gpiod_set_value(io_gpio, status);
return 1;
}

释放GPIO:
gpiod_put(io_gpio);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值