linux kernel GPIO operation

I learned the Linux kernel about 10 years ago, but the operation of GPIO at that time was simple and rude. Now the pin-ctrl gpio drives a bunch of dts. I don’t know where to start. After several days of tossing, I took a note so I didn’t forget it again. Again.

An operating register

Get the GPIO-related register address according to the chip manual (here s5p6818 is an example)

//这是芯片手册里给出的真实物理地址
#define PHYS_BASE_GPIOA_OUTDAT (0xC001A000)  //
#define PHYS_BASE_GPIOA_OUTEN  (0xC001A004)
#define PHYS_BASE_GPIOA_PAD	   (0xC001A018)
#define PHYS_BASE_GPIOA_FUNC0  (0xC001A020)
#define PHYS_BASE_GPIOA_FUNC1  (0xC001A024)

The physical address cannot be directly manipulated and needs to be processed by ioremap:
Parameter 1: Real physical address
Parameter 2: The length of the address space, in bytes, the arm register is generally 32, so 4

void __iomem *gpioa_outdat_addr;
void __iomem *gpioa_outen_addr;
void __iomem *gpioa_pad_addr;
void __iomem *gpioa_func0_addr;
void __iomem *gpioa_func1_addr;
gpioa_outdat_addr = ioremap(PHYS_BASE_GPIOA_OUTDAT,4);
gpioa_outen_addr = ioremap(PHYS_BASE_GPIOA_OUTEN,4);
gpioa_pad_addr = ioremap(PHYS_BASE_GPIOA_PAD,4);
gpioa_func0_addr =ioremap(PHYS_BASE_GPIOA_FUNC0,4);
gpioa_func1_addr =ioremap(PHYS_BASE_GPIOA_FUNC1,4);

The obtained void __iomem * value can be read with readl (address can be read) and written with writel (address can be written)

u32 data_en = readl(gpioa_outen_addr);
data_en = 0x000FFFE2;
writel(data_en,gpioa_outen_addr);

How to use these registers,
please refer to the chip manual and remember to release them after use:

iounmap(gpioa_outdat_addr);
iounmap(gpioa_outen_addr);
iounmap(gpioa_pad_addr);
iounmap(gpioa_func0_addr);
iounmap(gpioa_func1_addr);

The speed of readl and writel operating registers is very slow, and may not meet the speed requirements during GPIO simulation timing, but in fact the register read and write speed is very fast, but these two functions have added some safety measures. In pursuit of speed, you can use:
__raw_writel
__raw_readl
These are two inline functions, which only do address fetching and assignment:

static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
	*(volatile u32 __force *)addr = value;
}
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
	return *(const volatile u32 __force *)addr;
}

So you can read and write more directly:

u32 data_en =*(const volatile u32 __force *)gpioa_outen_addr;
data_en = 0x000FFFE2;
*(volatile u32 __force *)gpioa_outen_addr = value;

The disadvantage of this is that in some cases, it may be optimized by the compiler, resulting in unsuccessful assignment

Two use linux gpio driver

The advantage of directly operating the register is that it is fast and can operate multiple gpio pins at the same time. The disadvantage is that there are too many registers and setting the value is very cumbersome. In the above example, you need to set 5 registers to operate a GPIO, and you must find the corresponding bit , If you are not careful, you will be wrong, and one day may be spent in bit operations. The role of gpio driver is reflected.
GPIO operation API:

//申请GPIO,参数1:gpio 编号,参数2:gpio 名字 (自定义)
int gpio_request(unsigned gpio, const char *label)

//释放GPIO ,参数1:gpio编号
void gpio_free(unsigned gpio)

//设置GPIO为输出模式,同时将输出设为value 
//参数1:gpio编号,参数2:输出的值 (0或1)
static inline int gpio_direction_output(unsigned gpio, int value)

//设置GPIO为输入模式
static inline int gpio_direction_input(unsigned gpio)

//判断gpio是否有效,就是判断gpio的编号是否在范围内
//比如soc的所有gpio编号是0~128,如果输入编号在此范围则认为有效
//返回值:true 为有效,false为无效。
static inline int gpio_is_valid(unsigned int gpio)

//设置GPIO的状态,参数1:GPIO编号,参数2:设置的值(0或1)
static inline void gpio_set_value(unsigned int gpio, int value)

//获取GPIO的状态,参数1:GPIO编号
//返回值;GPIO 状态,0:GPIO低点位,1:GPIO高电位
static inline int gpio_get_value(unsigned int gpio)

The GPIO number is related to the BSP of soc and can be obtained by reading the relevant code.
s5p6818 has 5 GPIO ports (A, B, C, D, E) and each port has 32 pins, a total of 160, so they are numbered sequentially from 0 to 159, (A0=0, A1=1---- --E31=159)
This coding rule should be unified. The names of GPIO ports are different from chip to chip. Some are called GPIO0 GPIO1------
The second parameter of gpio_request is to give the applied gpio an individual name. The name is defined without any requirements. It is best to add some prefixes or suffixes for specialization to avoid repetition.

//这段代码将GPIOE_30 设置为输出模式并拉低,20us后再拉高
#define FPGA_POWER_GPIONUM     158     //GPIOE_30
//request PWOER GPIO
if(gpio_request(FPGA_POWER_GPIONUM,"FPGA_POWER")){
	gpio_direction_output(FPGA_POWER_GPIONUM,0);
	usleep(20);
	//因为已经设置为output模式,所以可以直接调用gpio_set_value
	//即使gpio为input模式也可以设置,只是不能作用到引脚
	gpio_set_value(FPGA_POWER_GPIONUM,1);
}

gpio_request This is mainly to judge whether it is occupied by other modules. If not, register and tell the GPIO system that I am occupied. If this function fails, basically other modules also use this GPIO. This problem is very common when migrating the system, because the wiring of your own board is very different from the demo, GPIO is often occupied when migrating with demo, but the demo code is generally set in the dts gpio pin, so just check the DTS Where is this pin configured?

Three GPIO interrupts

It is also implemented with GPIO driver API. It is too cumbersome to directly manipulate the registers. If you don't do it, your hair is running out!
Interruption alone, because it involves the interrupt API, (this is beyond the scope of *_*)

//根据gpio编号得到irq编号
static inline int gpio_to_irq(unsigned int gpio)

//使能中断,参数:irq编号
void enable_irq(unsigned int irq)

//禁用中断,参数:irq编号
void disable_irq(unsigned int irq)

// 申请中断
//参数1:中断号,参数2:中断处理函数,参数3:触发方式, 参数4:中断名(自定义)
//参数5:传递给中断处理函数的参数
//返回值:不为0表示失败。
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev)
	    
//释放中断
//参数1 :中断号,参数2 :中断处理函数
void free_irq(unsigned int irq, void *dev_id)

The interrupt number obtained by gpio_to_irq runs through the entire interrupt operation. The input parameter is the GPIO number mentioned above, provided that the GPIO can be used as an interrupt pin. This is related to soc. See the chip manual for details.
The second parameter of request_irq is the interrupt handling function, which is defined as follows:

irqreturn_t bc_irq_handler(int irq, void *dev_id)

The first parameter is the interrupt number. Different interrupt processing functions can be the same. The specific interrupt is distinguished by the interrupt number. The second parameter and the last parameter of request_irq.

The following code is to set the gpioa-20 pin to interrupt mode, the falling edge triggers, the processing function is bc_irq_handler, and the function name and interrupt number are printed in the interrupt processing function.

irqreturn_t bc_irq_handler(int irq, void *dev_id){
	printk("%s %d\n",__func__,irq);
}

#define FPGA_B_INT               20       // gpioa-20 intrupt
int b_irq = gpio_to_irq(FPGA_B_INT);
ret = request_irq(g_privdat->b_irq,bc_irq_handler,IRQF_TRIGGER_FALLING,"B int",NULL);
if(ret){
	printk("request_irq error: %d\n",b_irq);
	return;
}
enable_irq(b_irq);

Four gpio and dts

This section is also beyond the outline, it will involve DTS (device tree), but it mainly lists some API usage, and will not explain in depth. If you still have enough hair, write DTS notes.

Briefly talk about the correspondence between dts note and code.
Every dts note has a compatible field, as described in the following dts note:

//
bt_bcm {
	compatible = "bluetooth-platdata";
	uart_rts_gpios = <&gpio_c 6 GPIO_ACTIVE_LOW>; 
	uart_cts_gpios = <&gpio_c 5 GPIO_ACTIVE_LOW>; 
	pinctrl-names = "default", "rts_gpio";
	pinctrl-0 = <&serial1_flow>;
	pinctrl-1 = <&bt_flow_gpio>;

	reset-gpios    = <&gpio_b 26 GPIO_ACTIVE_HIGH>; 
	wake-gpios     = <&gpio_b 27 GPIO_ACTIVE_HIGH>;
	status = "okay";
};

Compatible is defined by itself, it has a one-to-one correspondence with the driver

static struct of_device_id bt_platdata_of_match[] = {
    { .compatible = "bluetooth-platdata" },
    { }
};

The above structure is defined in the driver and registered in the system, then the system will match the dts note and the driver, and call the probe function in the driver:

static int rfkill_rk_probe(struct platform_device *pdev){
	......
}

The input parameter of the probe function platform_device structure has pdev->dev->of_node and dts note content
. There are two ways to get gpio from the note:

//参数1 :对应的probe 函数输入参数下的pdev->dev->of_node 
//参数2 :note 中GPIO 列表的字段名
//参数3 :要取的gpio在列表中的下标
//参数4:gpio默认电位值
//返回值:GPIO编号
int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
			    int index, enum of_gpio_flags *flags)

//参数1:probe函数输入参数中的设备结构体pdev->dev
//参数2:note中的字段名
//参数3:要将gpio设置为何种状态
//返回值:gpio_desc 结构体,该结构体是对GPIO编号的包装。
struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
						       const char *con_id,
						       enum gpiod_flags flags)

Example: The
first type:

enum of_gpio_flags flags;
gpio = of_get_named_gpio_flags(node, "BT,reset_gpio", 0, &flags);

No need to explain note, "BT,reset_gpio" and the fields in note can be seen in the note example above.
0 means the subscript of the list.
To explain here, the field for setting GPIO is actually an array. Here, only one GPIO
BT is set in the "BT,reset_gpio" array , reset_gpio = <&gpio_b 26 GPIO_ACTIVE_HIGH>;
It can fill multiple gpio:

BT,reset_gpio    = <&gpio_b 26 GPIO_ACTIVE_HIGH  //index =0
					&gpio_c 10 GPIO_ACTIVE_HIGH             //index =1
					&gpio_a 11 GPIO_ACTIVE_HIGH>;         //index=2

In this case, the corresponding gpio number can be obtained by index.
flags is an output parameter, corresponding to GPIO_ACTIVE_HIGH

The second type;

struct gpio_desc *bt_reset;
bt_reset = devm_gpiod_get_optional(&pdev->dev, "reset",
			GPIOD_OUT_LOW);

This method is quite different from the first one. The two methods get the same gpio
1, but the second parameter substitution name is not the same, this is because devm_gpiod_get_optional will complete the name, and he will search for reset-gpios;
2 does not substitute the parameter index, the default is index 0, so it can’t handle multiple gpio settings.
3 The third parameter is input, and it will set gpio to this state instead of getting the state set in DTS, that is, it ignores the pin state in DTS Configuration.
4 The return value is the gpio_desc structure instead of the GPIO number. This structure is bound to the corresponding GPIO, and the GPIO number obtained by the first method points to the same GPIO pin as the gpio_desc obtained here

The gpio_desc structure is set with another set of api:

int gpiod_request(struct gpio_desc *desc, const char *label)
void gpiod_set_value(struct gpio_desc *desc, int value)
int gpiod_get_value(const struct gpio_desc *desc)
int gpiod_direction_input(struct gpio_desc *desc)
int gpiod_direction_output(struct gpio_desc *desc, int value)

It is different from the method in the second section in that the function name has an extra'd', and the input GPIO number is changed to the gpio_desc structure

There are many APIs about GPIO, here are some commonly used ones.

Guess you like

Origin blog.csdn.net/crazycat_dzw/article/details/109286002