【Linux学习笔记】pinctrl和gpio子系统

系列文章目录

开发板挂载根文件系统
设备树学习



一、pinctrl子系统

1.1 pinctrl子系统简介

Linux驱动讲究驱动分离与分层,pinctrl和gpio子系统就是驱动分离和分层思想下的产物,驱动分离与分层起始就是按照面对对象编程的设计思想而设计的设备驱动框架。
在之前的笔记中未使用pincrtl时,首先添加节点,在节点中设置reg属性,在驱动中获取reg的值来对PIN功能初始化,最后对复用功能初始化,驱动开发方式和裸机没什么区别。基本上和STM32标准库配置类似:

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE);  	//TIM5时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); 	//使能PORTE时钟	
	
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource5,GPIO_AF_TIM9); //GPIOE5复用为定时器14
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;           //GPIOE5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOE,&GPIO_InitStructure);              //初始化PE5

pinctrl子系统主要工作内容:
1、获取设备树中pin信息
2、根据获取到的pin信息来设置pin的复用功能
3、根据获取到的pin信息来设置pin的电气特性,比如上/下拉、速度、驱动能力等。
PIN可复用为I2C、SPI、GPIO。

1.2 pinctrl子系统的使用

1.2.1 配置设备树

打开开发板对应的设备树文件比如:imx6ull-alientek-emmc.dts,找到&iomuxc

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog_1>;
	imx6ul-evk {
		pinctrl_hog_1: hoggrp-1 {
			fsl,pins = <//属性名字一定要为 “fsl,pins”,pinctrl 驱动程序是通过读取 “fsl,pins” 属性值来获取 PIN 的配置信息
				MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
				MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059
				MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059
				MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058
			>;
};
......
//向iomuxc节点追加数据
//某个外设所使用的PIN都组织在一个子节点里面
//如果需要再iomuxc中添加我们自定义外设的PIN,那么需要新建一个子节点,然后将这个自定义外设的所有PIN配置信息都放到这个子节点中。

以这个为例

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19:MX6UL_PAD_UART1_RTS_B这个PIN后面的后缀GPIO1_IO19对应的是它的复用功能,这句的意思也就是将MX6UL_PAD_UART1_RTS_B复用为GPIO1_IO19。
0x17059:这个就是conf_reg寄存器的值,通过此值可以设置一个IO的上下拉、驱动能力和速度等,这里相当于设置寄存器IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B 的值为 0x17059。
Linux如何调取PIN信息?
linux 设备驱动文件在与 dts 中的设备板级硬件信息匹配的关键字是 compatible 属性。即比较驱动文件中 of_device_id 结构体元素的 .compatible 成员变量和 dts 文件中 node 中 compatible 属性两个字符串。如果匹配成功pinctrl-imx6ul.c 会完成 I.MX6ULL 的 PIN 配置工作。
教程上使用的是:文件drivers/pinctrl/freescale/pinctrl-imx6ul.c

1.2.2 设备树添加pinctrl节点的模板

1、在iomuxc节点中的imx6ul-evk子节点下添加pinctrl_test节点(节点的前缀一点要是pinctrl_),iomuxc节点在imx6ull-alientek-emmc.dts中

pinctrl_test: testgrp {
/* 具体的 PIN 信息 */
};

2、添加“fsl,pins”属性
设备树是通过属性来保存信息的,因此需要添加一个属性,属性名字一定要为“fsl,pins”,因为对于I.MX系列SOC而言,pinctrl驱动程序是通过读取“fls,pins”属性来获取PIN的配置信息和直接在根节点下创建节点读取节点信息还不一样

 pinctrl_test: testgrp {
	fsl,pins = <
	/* 设备所使用的 PIN 配置信息 */
	>;
};

3、在“fsl,pins”属性中添加具体的PIN配置信息

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

打完,收工!

二、gpio子系统

pinctrl子系统重点是设置PIN的复用和电气属性gpio子系统则是用于初始化GPIO并且提供相应的API函数,比如设置GPIO为输入输出,读取GPIO的值等。在设备树中添加gpio相关信息,然后就可以在驱动程序中使用gpio子系统提供的API函数来操作GPIO,好处就是屏蔽了GPIO的设置过程。
pincrtl子系统中设置了PIN的属性信息,在设备树根节点下创建节点:

	gpioled{
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "atkalpha-gpioled";
		pinctrl-names = "default";
		//这里会引用iomuxc节点下的pinctrl_led这个节点,iomuxc驱动会自动初始化这个节点下的所有PIN
		pinctrl-0 = <&pinctrl_led>;
		//描述了led-gpio使用了哪个IO,属性值一共有三个
		//&gpio1 3表示LED引脚所使用的IO属于GPIO1组
		//3表示GPIO1组的第3号IO,通过“gpio1 3”这两个值驱动程序就知道gpio-led使用的是GPIO1_IO03
		//GPIO_ACTIVE_LOW表示低电平有效
		led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
		status = "okay";
	};

这里没有设置GPIO的输入输出是因为在驱动程序的入口函数中设置的

ret = gpio_direction_output(gpioled.led_gpio, 1);

那么接下来就是gpio子系统的API函数

2.1 gpio子系统API函数

设置好设备树以后就可以使用gpio子系统提供的API函数来操作指定的GPIO,GPIO子系统向驱动开发人员屏蔽了具体的读写寄存器过程,这就是驱动分层与分离的好处。

2.1.1 gpio_request函数

用于申请一个GPIO管教,在使用GPIO之前一定要使用这个函数进行申请,函数原型如下:

int gpio_request(unsigned gpio, const char *label)
gpio:要申请的 gpio 标号,使用 of_get_named_gpio 函数从设备树获取指定 GPIO 属性信息,此函数会返回这个 GPIO 的标号。
label:给 gpio 设置个名字。
返回值:0,申请成功;其他值,申请失败。

2.1.2 gpio_free函数

如果不使用某个GPIO了,那么就可以调用这个函数进行释放。函数原型如下:

void gpio_free(unsigned gpio)
gpio:要释放的 gpio 标号。
返回值:无。

2.1.3 gpio_direction_input 函数

此函数用于设置某个 GPIO 为输入,函数原型如下所示:

int gpio_direction_input(unsigned gpio)
gpio:要设置为输入的 GPIO 标号。
返回值:0,设置成功;负值,设置失败。

2.1.4 gpio_direction_output 函数

此函数用于设置某个 GPIO 为输出,并且设置默认输出值,函数原型如下:

int gpio_direction_output(unsigned gpio, int value)
gpio:要设置为输出的 GPIO 标号。
value:GPIO 默认输出值。
返回值:0,设置成功;负值,设置失败。

2.1.5 gpio_get_value 函数

此函数用于获取某个 GPIO 的值(0 或 1),此函数是个宏,定义所示:

#define gpio_get_value __gpio_get_value int __gpio_get_value(unsigned gpio)
gpio:要获取的 GPIO 标号。
返回值:非负值,得到的 GPIO 值;负值,获取失败。

2.1.6 gpio_set_value 函数

此函数用于设置某个 GPIO 的值,此函数是个宏,定义如下

#define gpio_set_value __gpio_set_value void __gpio_set_value(unsigned gpio, int value)
gpio:要设置的 GPIO 标号。
value:要设置的值。
返回值:无

2.2 设备树中添加 gpio 节点模板

2.2.1 创建 test 设备节点

在根节点“/”下创建 test 设备子节点,如下所示:

test {
	/* 节点内容 */
};

2.2.2 添加 pinctrl 信息

test {
	pinctrl-names = "default";//添加 pinctrl-names 属性,此属性描述 pinctrl 名字为“default”。
 	pinctrl-0 = <&pinctrl_test>;//添加 pinctrl-0 节点,此节点引用 pinctrl_test 节点,表示 tset 设备的所使用的 PIN 信息保存在 pinctrl_test 节点中。
 	/* 其他节点内容 */
};

2.2.3 添加 GPIO 属性信息

我们最后需要在 test 节点中添加 GPIO 属性信息,表明 test 所使用的 GPIO 是哪个引脚,添加完成以后如下所示:

test {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_test>;
	gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;//test 设备所使用的 gpio。
};

2.3 与 gpio 相关的 OF 函数

2.3.1 of_gpio_named_count 函数

of_gpio_named_count 函数用于获取设备树某个属性里面定义了几个 GPIO 信息,要注意的是空的 GPIO 信息也会被统计到,比如:

	gpios = <0
	&gpio1 1 2
	0
	&gpio2 3 4>;

上述代码的“gpios”节点一共定义了 4 个 GPIO,但是有 2 个是空的,没有实际的含义。通过 of_gpio_named_count 函数统计出来的 GPIO 数量就是 4 个,此函数原型如下:

int of_gpio_named_count(struct device_node *np, const char *propname)
np:设备节点。
propname:要统计的 GPIO 属性。
返回值:正值,统计到的 GPIO 数量;负值,失败。

2.3.2 of_gpio_count 函数

和 of_gpio_named_count 函数一样,但是不同的地方在于,此函数统计的是“gpios”这个属性的 GPIO 数量,而 of_gpio_named_count 函数可以统计任意属性的 GPIO 信息,函数原型如下所示:

int of_gpio_count(struct device_node *np)
np:设备节点。
返回值:正值,统计到的 GPIO 数量;负值,失败。

2.3.3 of_get_named_gpio 函数

此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio5 7 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编号,此函数在驱动中使用很频繁!函数原型如下:

int of_get_named_gpio(struct device_node 	*np,
						const char 			*propname, 
						int 				index)
np:设备节点。
propname:包含要获取 GPIO 信息的属性名。
index:GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。
返回值:正值,获取到的 GPIO 编号;负值,失败。

END!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值