嵌入式Linux驱动开发(六)pinctrl和gpio子系统实验

**目的:**简化GPIO驱动开发。
***注意点:***每当配置一个PIN为GPIO时,需要确定该GPIO是否有被别的外设使用。-----------在vscode里对DTS搜索

1. pinctrl子系统

**作用:**设置一个PIN的复用和电气属性。
主要工作内容:
①获取设备树中 pin 信息。
②根据获取到的 pin 信息来设置 pin 的复用功能
③根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。

1.1 pinctrl子系统驱动

1)PIN配置信息:
imx6ull.dtsi中iomuxc的节点以及dts中&iomuxc的数据。
复用可以在imx6ul和6ull-pinfunc.h中查询。
以MX6UL_PAD_UART1_RTS_B_GPIO1_IO09这个复用为例:

//imx6ul-pinfunc.h
MX6UL_PAD_UART1_RTS_B_GPIO1_IO09	0X0090 0X031C 0X0000 0X5 0X0
<mux_reg=0X0090  conf_reg=0X031C  input_reg=0X0000  mux_mode=0X5  input_val=0X0>
/*
---------------------相关GPIO复用及电气设置请查阅手册中的IOMUXC章节---------------------
mux_reg是复用寄存器的偏移,iomuxc父节点地址0X020e0000,所以复用寄存器地址为0X020e 0090
conf_reg:0X020e0000 + 0X031C,电气配置寄存器的地址。
input_reg:偏移为0,表示UART1_RTS_B这个PIN没有input功能。
input_val:写入input_reg寄存器的值。
mux_mode:0X5表示复用为GPIO1_IO09
*/

//imx6ull-alientek-emmc.dts
MX6UL_PAD_UART1_RTS_B_GPIO1_IO09	0X17059
//0X17059是写给电气配置寄存器的

2)pinctrl驱动:
**找对应设备驱动文件的方法:**用compatible的值,在vscode中全局搜索,找到的对应.c文件就是驱动文件。
在设备树中添加pinctrl节点模板–如何在设备树中添加某个外设PIN信息:
假设一个test设备,使用了GPIO1_IO00这个PIN的GPIO功能。
①创建对应节点:
同一个外设的PIN都放在一个节点中,打开对应的dts,在iomuxc节点中imx6ul-evk子节点下添加pinctrl_test节点。
②添加"fsl,pins"属性:
I.MX系列的SOC,pinctrl驱动程序通过读取该属性值来获取PIN配置信息。
③添加PIN配置信息:

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

2. gpio子系统

如果pinctrl子系统将一个PIN复用为GPIO,接下来就需要调用gpio子系统,初始化GPIO并提供相应的API。
在设备树中添加GPIO相关信息,然后在驱动程序中使用gpio子系统提供的API来操作GPIO。
1)设备树中的gpio信息:
前面将UART1_RTS_B复用为GPIO1_IO19,作为SD的CD引脚。那么SD卡驱动程序需要建立这个映射关系,因此需要在dts中,SD卡对应的节点“usdhc1”下添加一个属性描述这个映射。

&usdhc1 {
	...
	/* pinctrl-3 = <&pinctrl_hog_1>; */
	cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;   //低电平有效
	...
}

2)gpio子系统API:
①gpio_requst:用于申请一个GPIO管脚。

int gpio_request(unsigned gpio, const char *label)
/*
para:要申请的gpio标号,给gpio设置的名字。
return:0表示成功
*/

②gpio_free:用于释放一个GPIO管脚。

void gpio_free(unsigned gpio)
//para:要申请的gpio标号

③gpio_direction_input:用于设置某GPIO为输入。

int gpio_direction_input(unsigned gpio)
/*
para:要设置输入的gpio标号
return:0表示成功
*/

④gpio_direction_output:用于设置某GPIO为输出。

int gpio_direction_output(unsigned gpio, int value)
/*
para:要设置输出的gpio标号,gpio默认输出值
return:0表示成功
*/

⑤gpio_get_value:用于获取某个 GPIO 的值(0 或 1),此函数是个宏。

#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned gpio)
/*
para:要获取的gpio标号
return:0表示成功
*/

⑥gpio_set_value:用于设置某个 GPIO 的值,此函数是个宏。

#define gpio_set_value __gpio_set_value
int __gpio_set_value(unsigned gpio, int value)
/*
para:要设置的gpio标号,设置的值
return:0表示成功
*/

3)设备树中添加gpio节点模板:
①在根节点下创建test设备节点。
②添加pinctrl信息,表示test设备的PIN信息在pincttrl_test节点中。
③添加GPIO属性信息。

test {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_test>;
	gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
};

4)与gpio相关的OF函数:
**①of_gpio_named_count:**用于获取设备树某个属性(任意属性)里面定义了几个 GPIO 信息。

int of_gpio_named_count(struct device_node *np, const char *propname)
/*
para:np设备节点,propname要统计的GPIO属性
return:正值表示统计到的GPIO数量,负值表示失败
*/

**②of_gpio_count:**统计的是“gpios”这个属性的 GPIO 数量。

int of_gpio_count(struct device_node *np)
/*
para:np设备节点
return:正值表示统计到的GPIO数量,负值表示失败
*/

**③of_get_named_gpio:**获取GPIO编号。
此函数会将设备树中类似<&gpio5 7 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编号

int of_get_named_gpio(struct device_node *np, const char *propname, int index)
/*
para:np设备节点,propname要统计的GPIO属性
	  index:GPIO 索引,一个属性里面可能包含多个 GPIO,此参数指定获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。
return:正值表示获取到的GPIO编号
*/

你可能感兴趣的:(驱动开发,linux,运维)