Article count:1385 Read by:1972833

Featured Content
Account Entry

【i.MX6ULL】Driver development - Pinctrl subsystem and GPIO subsystem light up the LED

Latest update time:2021-12-14
    Reads:

The essence of the previous two articles ( register configuration to light up the LED and device tree version of lighting the LED ) is to control the on and off of the LED through register configuration.

  • Using the direct operation register method is to write the register information related to the LED directly into the LED driver code. This is also a relatively conventional control method. But when the chip registers change, the underlying driver must be rewritten.
  • The method of using the device tree is to write the register information related to the LED into the device tree file. In this way, when the device information is modified, the device information can also be obtained through the interface function of the device tree, which improves the efficiency of the driver code. Reusability.
  • The Pinctrl subsystem and GPIO subsystem introduced in this article do not need to directly operate the registers, because these two subsystems have already implemented the operation of the registers for us. We only need to operate the API functions provided by these two subsystems. Can.

1 Pinctrl subsystem

The Pintrl subsystem, as the name suggests, is a system that manages pins. For example, if you want to light up an LED, that is, to control the high and low levels of the corresponding pins of the LED, you must first multiplex the pins corresponding to the LED as GPIO through the Pintrl subsystem. Function (Is this somewhat similar to the function of the MUX register used in the previous register configuration )?

1.1 iomuxc node in the device tree

How to use the Pintrl subsystem? In fact, it also depends on the device tree. Let's first understand the iomuxc node in the device tree . This node is the node corresponding to the IOMUXC peripheral and is responsible for the reuse of IO functions.

Open the device tree file corresponding to your development board (mine is imx6ull-myboard.dts), then find the iomuxc node, and first take a look at its basic structure:

&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog_1>;
imx6ul-evk {
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */
>;
};

pinctrl_csi1: csi1grp {
fsl,pins = <
MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088
MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088
MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088
MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088
MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088
MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088
MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088
MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088
MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088
MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088
MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088
MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088
>;
};
//省略...

Here we take the pinctrl_hog_1 plug-in sub-node as an example for analysis. It is a collection of Pins related to hot-swapping, such as the ID pin of USB OTG. The pinctrl_csi1 sub-node is the PIN used by csi peripherals. This article needs to control the brightness of the LED. If it is off, you need to create a corresponding node, and then put all the Pin configuration information of this custom peripheral into this child node.

1.2 Analysis of the meaning of macro definition

For the byte point pinctrl_hog_1, pay attention to the following:

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19	    0x17059 /* SD1 CD */

This is the configuration of the Pin. The configuration includes two aspects: one is to set the multiplexing function of the Pin , and the other is to set the electrical characteristics of the Pin .

The previous MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 macro definition is defined in arch/arm/boot/dts/imx6ul-pinfunc.h (note that imx6ull.dtsi will reference imx6ull-pinfunc.h , and imx6ull-pinfunc.h will reference imx6ul-pinfunc.h )

There are a total of 8 macro definitions starting with MX6UL_PAD_UART1_RTS_B, which represent 8 different functions of this IO.

In addition, the value defined by this macro is divided into 5 segments, and the value of each segment has a specific meaning:

  • 0x0090 mux_reg register offset address

  • **0x031C **conf_reg register offset address

  • 0x0000 input_reg register offset address (invalid here)

  • 0x5 mux_reg register value

  • 0x0 input_reg register value (invalid here)

2 GPIO subsystem

The GPIO subsystem, as the name suggests, is a system that manages GPIO functions. Its function is to initialize and configure GPIO (is this function somewhat similar to the PAD register used in the previous register configuration ), and provides an external API interface. After using the GPIO subsystem, you do not need to operate the registers yourself. You can control the GPIO by calling the API functions provided by the GPIO subsystem.

2.1 gpio information in the device tree

Still taking the hot-swappable node as an example:

UART1_RTS_B is multiplexed as GPIO1_IO19, and it is judged whether the SD card is inserted by reading its high and low levels.

So how does the SD card driver know that the CD pin is connected to GPIO1_IO19? You still need to tell the driver from the device tree. Just add an attribute under the SD card node in the device tree to describe the CD pin of the SD card:

The attribute cd-gpios describes which IO is used by the CD pin of the SD card. There are three attribute values:

  • &gpio1 indicates that the IO used by the CD pin belongs to the GPIO1 group
  • 19 represents IO No. 19 of GPIO1 group
  • GPIO_ACTIVE_LOW means low level is active

Based on the above information, the SD card driver can use GPIO1_IO19 to detect the CD signal of the SD card.

2.2 gpio subsystem API functions

2.2.1 gpio_request/free

  • gpio_request

Used to apply for a GPIO pin

/**
* gpio: 要申请的gpio标号(使用of_get_named_gpio函数从设备树获取指定GPIO属性信息时返回的标号)
* label: 给gpio设置个名字
* return: 0-申请成功 其他值-申请失败
*/

int gpio_request(unsigned gpio, const char *label)
  • gpio_free

Used to release a GPIO pin

/**
* gpio: 要释放的gpio标号
* return
*/

void gpio_free(unsigned gpio)

2.2.2 gpio_direction_input/output

  • gpio_direction_input

Used to set a certain GPIO as input

/**
* gpio: 要设置为输入的GPIO标号
* return: 0-设置成功 负值-设置失败
*/

int gpio_direction_input(unsigned gpio)
  • gpio_direction_output

This function is used to set a GPIO as output and set the default output value

/**
* gpio: 要设置为输出的GPIO标号
* value: GPIO默认输出值
* return 0-设置成功 负值-设置失败
*/

int gpio_direction_output(unsigned gpio, int value)

2.2.3 gpio_get_value/set_value

  • gpio_get_value

This function is used to get the value of a certain GPIO (0 or 1)

#define gpio_get_value  __gpio_get_value
/**
* gpio: 要获取的gpio标号
* return: 非负值-得到的gpio值 负值-获取失败
*/

int __gpio_get_value(unsigned gpio)
  • gpio_set_value

Used to set the value of a certain GPIO

#define gpio_set_value  __gpio_set_value 
/**
* gpio: 要设置的gpio标号
* value: 要设置的值
* return
*/

void __gpio_set_value(unsigned gpio, int value)

2.3 OF functions related to gpio

2.3.1 of_gpio_named_count

Used to obtain several GPIO information defined in a certain attribute of the device tree.

/**
* np: 设备节点
* propname: 要统计的gpio属性
* return: 正值-统计到的gpio数量 负值-失败
*/

int of_gpio_named_count(struct device_node *np, const char *propname)

2.3.2 of_gpio_count

Count the number of GPIOs with the attribute "gpios"

/**
* np: 设备节点
* return: 正值-统计到的gpio数量 负值-失败
*/

int of_gpio_count(struct device_node *np)

2.3.3 of_get_named_gpio

Get GPIO number

/**
* np: 设备节点
* propname: 包含要获取gpio信息的属性名
* index: gpio索引(一个属性里面可能包含多个gpio)
* return: 正值-获取到的gpio编号 负值-失败
*/

int of_get_named_gpio(struct device_node *np,
const char *propname,
int index)

3 Pinctr version LED driver

The basic situation of the Pinctrl subsystem and GPIO subsystem is introduced above. Let's use them to realize the on and off control of LED.

3.1 Modify device tree file

Modify imx6ull-myboard.dts and create a child node named pinctrl_led under the imx6ull-evk byte point of the iomuxc node. The node content is as follows:

pinctrl_gpioled: ledgrp{
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x10b0
>;
};
  • MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 means reusing this io as GPIO

  • 0x10b0 represents the configuration value of the PAD register. The specific meaning is as follows, which was introduced in the previous article (Driver Development 4--Lighting the LED (Register Version)).

    /*寄存器SW_PAD_SNVS_TAMPER3设置IO属性
    *bit 16:0 HYS关闭
    *bit [15:14]: 00 默认下拉
    *bit [13]: 0 kepper功能
    *bit [12]: 1 pull/keeper使能
    *bit [11]: 0 关闭开路输出
    *bit [7:6]: 10 速度100Mhz
    *bit [5:3]: 110 R0/6驱动能力
    *bit [0]: 0 低转换率
    */

Create an LED node named gpioled under the root node with the following content:

/*pinctrl led*/
gpioled {
compatible = "myboard,gpioled";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpioled>;
led-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
status = "okay";
};
  • pinctrl-0 sets the pinctrl node corresponding to the PIN used by the LED
  • led-gpio specifies the GPIO used by the LED. Here is IO03 of GPIO5, which is active at low level.

3.2 Check whether the pin usage conflicts

Because the device tree file (imx6ull-myboard.dts) used by my development board is modified from the device tree file (imx6ull-14x14-evk.dts) officially provided by NXP, the configuration of some pins may be different from my own. The development boards are different, so you need to check whether there are any usage conflicts.

The MX6ULL_PAD_SNVS_TA MPER3__GPIO5_IO03 added this time does not conflict with other pins in the file, so there is no need to modify it.

3.3 Modify LED driver file

Make modifications to the driver file of the device tree version in the previous article. The main modifications are as follows.

The header file needs to add one:

#include <linux/of_gpio.h>

The device structure is changed to gpio_led:

/* gpioled设备结构体 */
struct gpioled_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
struct device_node *nd; /* 设备节点 */
int led_gpio; /* led使用的GPIO编号*/
};

struct gpioled_dev gpioled; /* led设备 */

The hardware initialization part is the main modification. This time, there is no need to read registers from the device tree, and there is no need to perform I/O memory mapping by yourself. Instead, the API function of the gpio subsystem is used to map the LED's GPIO. To configure:

static int gpioled_hardware_init(void)
{
int ret;

/* 获取设备树中的属性数据 */
/* 1、获取设备节点:gpioled */
gpioled.nd = of_find_node_by_path("/gpioled");
if(gpioled.nd == NULL)
{
printk("gpioled node not find!\r\n");
return -EINVAL;
}
else
{
printk("gpioled node find!\r\n");
}

/* 2、获取gpio属性, 得到LED编号 */
gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0);
if(gpioled.led_gpio < 0)
{
printk("can't get led-gpio!\r\n");
return -EINVAL;
}
else
{
printk("led-gpio num = %d\r\n", gpioled.led_gpio);
}

/* 3、设置GPIO为输出, 并默认关闭LED */
ret = gpio_direction_output(gpioled.led_gpio, 1);
if(ret < 0)
{
printk("can't set led-gpio!\r\n");
}

return 0;
}

When switching the LED on and off, you no longer need to directly operate the register. You can also use the API function to operate:

static ssize_t gpioled_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
//省略...

if(ledstat == LEDON)
{
gpio_set_value(dev->led_gpio, 0); /* 打开LED灯 */
printk("led on!\n");
}
else if(ledstat == LEDOFF)
{
gpio_set_value(dev->led_gpio, 1); /* 关闭LED灯 */
printk("led off!\n");
}

return 0;
}

4 Experimental tests

4.1 Compiler

  • Compile the device tree file (.dtb). Just like the experiment of lighting up the LED in the device tree in the previous article, first copy the device tree file to the nfs file system location, then start the development board from the network, and check the serial port to see if there is any added device tree. gpioled node:
  • Compile the LED driver file (.ko) and copy it to the rootfs/lib/modules/4.1.15 directory:
  • The LED application program does not need to be modified. You can still use the program used in the previous register version to light up the LED experiment.

4.2 Testing

The test method is the same as before, loading the driver file first, and then calling the application to control the LED on and off:

The effect is the same as the previous effect of lighting up the LED in the register version and lighting up the LED in the device tree version.

5 Summary

This article introduces the use of Pinctrl subsystem and GPIO subsystem to light up the LED. The biggest difference from the previous register version to light up the LED and the device tree version to light up the LED is that there is no need to directly operate the register , but to use API functions. To configure GPIO, the specific operation register is implemented inside the API function, and we do not need to perform cumbersome register operations.

This article is basically the same as the previous article's device tree version of the programming process for lighting up the LED, because both require the use of the device tree . The main difference from the previous article is that there is no need to write register information into the device tree, and then from The device tree obtains the manual configuration register.

end



A mouthful of Linux


Follow and reply [ 1024 ] Massive Linux information will be given away


Collection of wonderful articles

Article recommendation

【Album】 ARM
【Album】 Fans Q&A
【Album】 All original works
Album Introduction to linux
Album Computer Network
Album Linux driver


Click " Read the original text " to view more sharing, welcome to share, collect, like, and watch

 
EEWorld WeChat Subscription

 
EEWorld WeChat Service Number

 
AutoDevelopers

About Us Customer Service Contact Information Datasheet Sitemap LatestNews

Room 1530, Zhongguancun MOOC Times Building,Block B, 18 Zhongguancun Street, Haidian District,Beijing, China Tel:(010)82350740 Postcode:100190

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号